Archive

Archive for the ‘Reading’ Category

代码之道 -- 摘要

July 31st, 2010 cashplk No comments

1. 如何集中精力、避免打扰?


I.M.Wright提倡的方法是:在工作时,把邮件通知提示等都尽量关闭,然后安心做自己的工作;定期的(比如,每隔半小时)浏览收到的邮件,并且在查 看邮件时尽力把它完整处理掉,避免情境的切换。你可能会认为这样会导致某些低优先级的邮件浪费时间,但I.M.Wright却认为你在过后再次切换到这封邮件所消耗的精力和时间要比即时处理还要多。

I.M.Wright 提出要想避免被打扰,还可以“让自己消失”,去一个没人能找到你的地方,使用笔记本电脑和远程桌面安心工作,或者选择一个其他人不在的时候工作,比如早上早一点来公司,晚上回家用远程桌面工作。在这样一个安静的地方和时刻,你就可以抛开不必要的困扰,集中精力做一些工作。

笔者对这个观点非常赞同,也是自己之前亲身实践过的。一段时间以来,笔者坚持早上八点半到公司,此时偌大的办公区基本空无一人,然后带上笔记本电脑,找一个小会议室,一直工作到上午10点钟才回到自己的办公桌。这段时间非常的安静,不论上班的同事如何来来往往,笔者都不受干扰,集中处理一些事情,效率很高, 即使在平常工作时间,也会尽量多呆在安静的地方。同时,笔者发现一个有趣的现象:当我呆在办公桌的时候,时不时的就会有同事询问各种各样的问题,小到一个域名对应的IP地址,大到项目计划的制定。但是,一旦我呆在会议室工作时,这些口头的问题就不翼而飞了,小的问题同事们可以独立解决,大的问题会通过正式 的邮件和会议进行交流,这样大家的工作效率都会有所提高——因为极大减少了彼此的情境切换次数。

2. 平衡工作和生活

这个话题对程序员来说有些沉重和苦涩,软件开发似乎是个工作和生活严重失衡的职业。不过,I.M.Wright认为这不是命运注定,他在应聘微软的时候,就向未来的上司提出,他非常顾家,需要保证正常的工作时间,早上送孩子上学,晚上回家用餐,而老板完全同意了他的要求,并且说话算话。I.M.Wright提出了一个平衡工作和生活的五步原则:

  1. 了解并接受你选择的生活方式。
  2. 跟你的管理者一起设置一些基本原则。
  3. 不要默默妥协。
  4. 必要的时候使用“远程访问服务”和远程桌面访问。
  5. 抛开分离造成的精神分裂错觉。

具体的说,你需要了解你自己,好好思考一下你的工作目的是什么,事业和生活的优先级是什么,你的忍耐程度是多大,一旦把这些问题想明白了,你就会在平衡问题上做出正确的选择;把自己制定的原则告诉你的上司,不要担心你的工作和前途,在第一步时你已经把这些问题和限度考虑清楚。I.M.Wright发现这种交流反倒会使你赢得上司的尊重,因为你具有强烈的自信和清晰的价值观;在工作中,偶尔的破例是可以容忍的,但是如果经常出现超出原则的情况,你就需要找机会重申你的态度,因为一旦你很容易就妥协了,上司会认为你并不在意你自己指定的原则(如果连你自己都不在乎,又能指望谁来在乎呢?)。他可能会提出越来越多的要求,直到你的原则一退再退,你原先的努力就白费了;如果你热爱自己的工作而且的确很重要,可以在家里通过远程访问等方式访问;不要试图把工作和生活分开,保持一个统一的心态,避免情景切换。

程序员的自我修养 -- 链接,装载与库(上)

June 29th, 2010 cashplk No comments

第一部分  简介

第一章 温故而知新

1.1 从 Hello World说起
对于下面这些问题,你的脑子能够马上反应出一个很清晰又很明确的答案吗?
程序为什么要被编译器编译了才可以运行?
编译器在把C语言程序转换成可以执行的机器码的过程中做了什么,怎么做的?
最后编译出来的可执行文集那里面是什么?除了机器码还有什么?它们怎么存放的,怎么组织的?
#include<stdio.h>是什么意思?把stdio.h包含进来意味着什么?C语言库又是什么?它怎么实现的?
不同的编译器(Microsoft VC,GCC)和不同的硬件平台(x86,SPARC,MIPS,ARM),以及不同的操作系统(Windows,Linux,UNIX,Solaris),最终编译出来的结果一样吗?为什么?
Hello World程序是怎么运行起来的?操作系统是怎么装载它的?它从那儿开始执行,到哪儿结束?main函数之前发生了什么?main函数结束以后又发生了什么?
printf是怎么实现的?它为什么可以有不定数量的参数?为什么它能够在终端上输出字符串?
Hello World程序在运行时,它在内存中是什么样子的?

1.3 站的高,望得远
计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决。

1.5 内存不够怎么办
问题有3个:
  1,地址空间不隔离
  2,内存使用效率低
  3,程序运行的地址不确定

最开始人们使用的是一种叫做 分段(Segmentation)的方法,基本思路是把一段与程序所需要的内存空间大小的虚拟空间映射到某个地址空间。可以解决第一个和第三个问题。用更小粒度的内存分割和映射的方法,使得程序的局部性原理得到充分的利用,大大提高了内存的使用率。这种方法就是分页(Paging)。

分页的基本方法是把地址空间人为地等分成固定大小的页,每一页的大小由硬件决定,或硬件支持多种大小的页,由操作系统选择决定页的大小。

1.6 众人拾柴火焰高

1.6.1 线程基础
线程(Thread),有时被称为轻量型进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。通常意义上,一个进程由一个到多个线程组成,各个线程之间共享程序的内存空间(包括代码段,数据段,堆等)及一些进程级的资源(如打开文件和信号)。
线程的访问权限
    1,栈(尽管并非完全无法被其他线程访问,但一般情况下仍然可以认为是私有的数据)。
    2,线程局部存储(Thread Local Storage,TLS)。线程局部存储是某些操作系统为线程单独提供的私有空间,但通常只具有很有限的容量。
    3,寄存器(包括PC寄存器),寄存器是执行流的基本数据,因此为线程私有。

线程调度与优先级

在单处理器对应多线程的情况下,并发是一种模拟出来的状态。操作系统会让这些多线程程序轮流执行,每次仅执行一小段时间,这样每个线程就“看起来”在同时执行,这样的一个不断在处理器上切换不同的线程的行为称之为线程调度(Thread Schedule)。

线程调度自多任务操作系统问世以来就不断地被提出不同的方案和算法。现在主流的调度方式尽管各不相同,但都带有优先级调度(Priority Schedule)和轮转法(Round Robin)的痕迹。所谓轮转法,即是之前提到的让各个线程轮流执行一小段时间的方法。这决定了线程之间交错执行的特点。而优先级调度则决定了线程按照什么顺序轮流执行。

在优先级调度的环境下,线程的优先级改变一般有三种方式:

      1,用户指定优先级。 
      2,根据进入等待状态的频繁程度提升或降低优先级。
      3,长时间得不到执行而被提升优先级。
Linux的多线程
Linux对多线程的支持颇为贫乏,事实上,在Linux内核中并不存在真正意义上的线程概念。Linux将所有的执行实体(无论是线程还是进程)都称为任务(Task),每一个任务概念都类似于一个单线程的进程,具有内存空间,执行实体,文件资源等。不过,Linux下不同的任务之间可以选择共享内存空间,因此在实际意义上,共享了同一个内存空间的多个任务构成了一个进程,这些任务也就成了这个进程的线程。

第二部分 静态链接

第二章 编译和链接


2.1 被隐藏了的过程
GCC编译可以分解为4个步骤,分别是预处理(Prepressing),编译(Compilation),汇编(Assembly)和链接(Linking)。

2.1.1 预编译
预编译过程主要处理那些源代码文件中的以“#”开始的预编译指令。主要处理规则如下:
1,将所有的#define删除,并且展开所有的宏定义。
2,处理所有条件预编译指令。
3,处理#define预编译指令,将被包含的文件插入到该预编译指令的位置。
4,删除所有的注释 // 和 /* */。
5,添加行号和文件名标识,以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示行号。
6,保留所有的#pragma编译器指令,因为编译器需要使用它们。

2.1.2 编译
就是把预处理完的文件进行一系列词法分析,语法分析,语义分析及优化后产生对应的汇编代码文件,这个过程往往是我们所说的整个程序构建的核心部分,也是最复杂的部分之一。gcc这个命令只是对后台程序的包装,它会根据不同的参数要求去调用预编译编译程序ccl,汇编器as,连接器ld。

2.1.3 汇编
将汇编代码转变成机器可以执行的指令,每一个汇编语句几乎都对应一条机器指令。输出目标文件(Object File)。

2.1.4 链接
将目标文件链接为可执行文件。


2.2 编译器到底做了什么
编译过程一般可以分为6步:扫描,语法分析,语义分析,源代码优化,代码生成和目标代码优化。

2.2.1 词法分析
首先源代码被输入到扫描器(Scanner),扫描器的任务很简单,它只是简单地进行词法分析,运用一种类似于有限状态机(Finite State Machine)的算法可以轻松地将源代码的字符序列分割成一系列的记号(Token)。

2.2.2 语法分析
接下来语法分析器(Grammar Parser)将对由扫描器产生的记号进行语法分析,从而产生语法树(Syntax Tree),整个分析过程采用了上下文无关语法(Context-free Grammar)的分析手段。简单的讲,由语法分析器生成的语法树就是以表达式(Expression)为节点的树。对于不同的编程语言,编译器的开发者只须改变语法规则,而无须为每个编译器编写一个语法分析器,所以它又被称为“编译器编译器”(Compiler Compiler)。

2.2.3 语义分析
接下来进行的是语义分析,由语义分析器(Semantic Analyzer)来完成。仅仅是完成了对表达式的语法层面的分析,但是它并不了解这个语句是否真正有意义。经过语义分析阶段以后,整个语法树的表达式都被标识了类型,如果有些类型需要式转换,语义分析程序会在语法树中插入相应的转换节点。

2.2.4 中间语言生成
使得编译器可以被分为前端和后端。前端负责产生机器无关的中间代码,后端将中间代码转换成目标机器代码。

2.2.5 目标代码生成与优化
编译器后端主要包括代码生成器(Code Gnerator)和目标代码优化器(Target Code Optimizer)。

2.4 模块拼装–静态链接
把每个源代码模块独立编译,然后按照需要将它们“组装”起来,这个组装模块的过程就是链接。链接的主要内容就是把各个模块之间相互引用的部分都处理好,使得各个模块之间能够正常地链接。链接过程主要包括了地址和空间分配(Address and Storge Allocation),符号决议(Symbol Resolution)和重定位(Relocation)等这些步骤。

第三章 目标文件里面有什么
3.1 目标文件的格式
现在PC平台流行的可执行文件格式(Executable)主要是Windows下的PE(Portable Executable)和Linux的ELF(Executable Linkable Format),它们都是COFF(Common file Format)格式的变种。目标文件就是源代码编译后但未进行链接的那些中间文件(Windows 的 .obj 和 Linux 的 .o),它跟可执行文件的内容与结构很相似,所以一般跟可执行文件格式一起采用一种格式存储。

3.2 目标文件是什么样的
程序源代码编译后的机器指令经常被放在代码段(Code Section)里,代码段常见的名字有”.code”或“.text”;全局变量和局部静态变量数据经常放在数据段(Data Section),数据段的一般名字都叫“.data”。
总体来说,程序源代码被编译以后主要分成两种段:程序指令和程序数据。代码段属于程序指令,而数据段和.bss段属于程序数据。
把程序的指令和数据存放分开,主要有以下好处:
1,当程序被装载后,数据和指令分别被映射到两个虚存区域。由于数据区域对于进程来说是可读写的,而指令区域对于进程来说是只读的,所以这两个虚存区域的权限可以被分别设置成可读写和只读。这样可以防止程序的指令被有意或无意地改写。
2,指令区和数据区的分离有利于提高程序的局部性。现代CPU的缓存一般都被设计成数据缓存和指令缓存分离,所以程序的指令和数据被分开存放对CPU的缓存命中率提高有好处。
3,当系统中运行着多个该程序的副本时,它们的指令都是一样的,所以内存中只须要保存一份该程序的指令部分
第四章 静态链接
4.1 空间与地址分配
现在的链接器分配策略都是相似段合并。使用这种方法的链接器一般都采用一种叫 两步链接(Two-pass Linking)的方法。
第一步,空间与地址分配,扫描所有的输入目标文件,获得它们各个段的长度,属性和位置,并且将输入目标文件中的符号表中所有的符号定义和符号引用收集起来,统一放到一个全局符号表。这一步中,链接器将能获得所有输入目标文件的段长度,并且将它们合并,计算出输出文件中各个段合并后的长度与位置,并建立映射关系。
第二步,符号解析与重定位,
使用上面第一步收集到的所有信息,读取输入文件中段的数据,重定位信息,并且进行符号解析与重定位,调整代码中的地址等。事实上第二步时链接过程的核心,特别是重定位过程。

4.2 符号解析与重定位

4.2.1 重定位

4.2.2 重定位表
保存这些与重定位相关的信息,在ELF文件中往往是一个或多个段。

4.2.3 符号解析
其实重定位过程也伴随着符号的解析过程,每个目标文件都可能定义一些符号,也可能引用到定已在其他目标文件的符号。重定位的过程中,每个重定位的入口都是对一个符号的引用,那么当链接器须要对某个符号的引用进行重定位时,它就要确定这个符号的目标地址。这时候链接器就会去查找由所有输入目标文件的符号表组成的全局符号表,找到相应的符号然后进行重定位。

4.2.4 指令修正方式
不同的处理器指令对于地址的格式和方式都不一样。这些寻址方式有以下几方面的区别:
1,近址寻址或远址寻址。
2,绝对寻址或相对寻址。
3,寻址长度为8位,16位、32位或64位。
绝对寻址修正和相对寻址修正的区别就是绝对寻址修正后的地址为该符号的实际地址;相对寻址修正后的地址为符号距离被修正位置的地址差。

4.4 C++相关问题
C++的一些语言特性使之必须由编译器和链接器共同支持才能完成工作。最主要的有两个方面,一个是C++的重复代码消除,还有一个就是全局构造与析构。

4.4.1 重复代码消除
C++编译器在很多时候会产生重复的代码,比如模板(Template),外部内联函数(Extern Inline Function)和虚函数表(Virtual Function Table)都有可能在不同的编译单元里产生相同的代码。
一个比较有效的做法是将每个模板的实例代码都单独地存放在一个段里,每个段只包含一个模板实例。

第五章 WINDOWS PE/COFF


 

Categories: Reading Tags: , , ,

程序员修炼之道:从小工到专家

June 29th, 2010 cashplk No comments
71
注重实效的程序员有哪些特征:
1,早期的采纳者/快速的改编者。具有技术和技术上的直觉,喜欢试验各种事物,给你一样新东西,很快就能把握它,并把它与你的知识的其它部分结合在一起。
2,好奇。
3,批判的思考者。
4,有现实感。会设法理解你面临的每个问题的内在本质。
5,多才多艺。尽力熟悉广泛的技术和环境,并且努力工作,以与各种新发展并肩前行。尽管你现在的工作也许只要求你成为某方面的专才,你却总是能够转向新的领域和新的挑战。

第一章 注重实效的哲学

注重实效的程序员的特征是什么? 能够越出直接的问题去思考,总是设法把问题放在更大的语境中,总是设法注意更大的图景。
注重实效的编程源于注重实效的思考的哲学。本章将为这种哲学设立基础。

我的源码让猫给吃了

注重实效的程序员对他自己的职业生涯负责,并且不害怕无知或错误,这肯定并非是编程最令人愉悦的方面,但它肯定会发生。
发生这样的事情,我们要设法尽可能职业地处理它们,这意味着诚实和坦率。我们可以为我们的能力自豪,但对于我们的缺点--还有我们的无知和错误--我们必须诚实。

软件的熵
破窗理论

石头汤与煮青蛙

足够好的软件

你的知识资产
经营你的资产
1,定期投资。
2,多元化,知道的不同的事情越多,就越有价值。
3,管理风险,
4,低买高卖,
5,重新评估和平衡

目标:
1,每年至少学习一种新语言
2,每季度阅读一本技术书籍
3,也要阅读非技术书籍
4,上课
5,参加本地用户组织
6,试验不同的环境
7,跟上潮流
8,上网

挑战:
1,这周就开始学习一种新语言。
2,开始阅读一本新书
3,出去和你的当前项目无关的人,或是其他公司的人谈谈技术。

第二章 注重实效的途径
重复的危害
重复是怎样发生的:
1,强加的重复,
2,无意的重复,
3,无耐性的重复,
4,开发者之间的重复,
第三章 基本工具
强力编辑
选一种编辑器,彻底了解它,并将其用户所有的编辑任务。如果你用一种编辑器进行所有的文本编辑活动,你就不必停下来思考怎样完成文本操作:必需的键击将成为本能反应。编辑器将成为你双手的延伸;键会在划过文本和思想时歌唱起来,这就是我们的目标。

文本操作

第四章 注重实效的偏执

何时使用异常
什么是异常情况
异常很少应作为程序的正常流程的一部分使用;异常应保留给意外事件。

第五章 弯曲,或折断

元程序设计
动态配置: 要配置,不要集成。
元数据驱动的应用:
将抽象放进代码,细节放进元数据。

好处:
迫使你解除你的设计的耦合,从而带来更灵活,可适应性更好的程序。
迫使你通过推迟细节处理,创建更健壮,更抽象的设计 -- 完全推迟到程序之外。
无需重新编译应用,你就可以对其进行定制。

编写单元测试
通过使测试代码易于找到,你是在给使用你代码的开发者提供两样无价的资源:
1,一些例子,说明怎样使用你的模块的所有功能。
2,用以构建回归测试,以验证未来对代码的任何改动是否正确的一种手段。
使用测试装备
不管你决定采用的技术是什么,测试装备都应该具有以下功能:
1.用以指定设置与清理的标准途径。
2.用以选择个别或所有可用测试的方法。
3.分析输出是否是预期(或意外)结果的手段。
4.标准化的故障报告形式。

第七章 在项目开始之前
需求之坑
完美,不是在没有什么需要增加,而是在没有什么需要去掉时达到的。

Categories: Reading Tags: , ,

505读书系列(1) -- 思科九年

May 2nd, 2010 cashplk No comments

又聊到了关于人生境界的话题。

  “三个层面,”老雍说,“第一,解决温饱。以前你们怎么样我不清楚,进了思科这个问题应该解决了吧?要是还没有解决,告诉我,我去问问老冯。哈哈哈。”

  “第二,生活品质。吃饱了穿暖了,要想着怎么样吃得更健康,穿得更有品位,对吧?同样是打伞,别人打的是普通折叠伞,你打的是由陈逸飞设计而且有他签名的伞;同样是喝酒,别人喝长城干红,你喝的是1929年法国勃艮第区酒庄的窖藏;这就不一样啦。”

  “第三,就是玩啦。我意思是,要让自己有能力去玩,而且要玩得漂亮,玩得与众不同。这就是境界。

 

记得之后有一个销售对我说过,做过销售这个行当,你基本上就了解你所处的这个社会了,是那种真正的了解。“然后,”他说,“你就可以游刃有余。”
  这是我第一次开始感受销售这个行当对我的吸引力。

想想也是。经济学原理说人们在选择一些东西的时候,就一定要放弃另外一些东西。这个世界的有趣就在于当你选择的时候,并没有一个所谓的正确答案在试卷背后等着你;而当你若干年后回顾自己当初这个决定的时候,所谓对错都已经毫无意义,你已经伴随着你当时的选择走了这么多年。

  你会无奈地对自己笑笑说,这就是命。

 记得读高三的时候被功课的重压弄得心力交瘁,后来一本卡耐基写的心理训练的小册子拯救了我。上面对我有用的只有一句话:把现在的事做好,不要为以后的事情预支烦恼。

  直到现在,我才意识到销售这个工作对我有点吸引力的原因,那就是人——一个个形态迥异内涵深远的人,他们各自带着几十年的年轮向你展示这个世界在人身上留下的真实印记,也向你展示各自背后那个既不像童话那么美好也不像悲剧那么煽情的错综丛林。和他们打交道,让你感觉好像放大了自己时间的容量,让你以原来没有的速度切入到自己生活了这么久的社会系统深处,这个深处,是一片我并不熟悉并且对之充满了好奇的世界。

————————————————————————

对于图书,只有单纯的观看,看过之后,或许有所感悟。或许只是笑笑。不管真假,看到自己喜欢的即可。就当一部电影,不过是别样的表达方式而已。

Categories: Reading Tags: , ,

高效程序员的45个习惯 读后感

March 28th, 2010 cashplk No comments

第一章 敏捷 -- 高效软件开发之道

敏捷开发宣言:

1,个体和交互胜过过程和工具

2,可工作的软件胜过面面俱到的文档

3,客户协作胜过合同谈判

4,响应变化胜过遵循计划

敏捷方法可以快速地响应变化,它强调团队合作,人们专注于具体可行地目标(实现真正可以工作的软件),这就是敏捷的精神。

它要求团队中的每一个人(包括与团队合作的人)都具备职业精神,并积极地期望项目能够获得成功,它并不要求所有人都是有经验的专业人员,但必须具有专业的工作态度 --每个人都希望尽最大可能做好自己的工作。

精辟概括:

敏捷开发就是在一个高度协作的环境中,不断地使用反馈进行自我调整和完善。

敏捷工具箱

1,Wiki:用来协作,实现知识共享。

2,版本控制:

3,单元测试:用代码来检查代码。

4,自动构建:全自动化,持续集成。

第二章 态度决定一切

专业的态度应该着眼于项目和团队的积极结果,关注个人和团队的成长,围绕最后的成功展开工作。集中精力,你是为做事而工作。

实行代码复审,不仅有助于代码更好理解,而且是发现bug最有效的方法之一。

另一种防止代码难懂的重要技术就是单元测试。帮助你很自然地把代码分层,分成很多可管理的小块,这样就得到设计更好、更清晰的代码。

第三章 学无止境

如何跟上技术变化的步伐?

1,迭代和增量式的学习。每天计划用一段时间来学习新技术,它不需要很长时间,但需要经常进行。记下那些你想学习的东西。

2,了解最新行情。最新的博客列表请参考 pragmaticprogrammer.com

3,参加本地的用户组活动。

4,参加研讨会。

5,如饥似渴地阅读。

第四章 交付用户想要的软件

提早集成,频繁集成。


第六章 敏捷编码

良好的面向对象设计原则建议:应该编写内聚的代码,要保持代码条理清晰,告知,不要询问。最后,通过设计能够根据契约进行替换的系统,可以在不确定的未来中保持代码的灵活性。

Categories: Reading Tags: , ,

卓有成效的程序员读后感

March 2nd, 2010 cashplk 1 comment

本书对应豆瓣的链接是:http://www.douban.com/subject/3558788/

第二章 加速法则

Quicksilver:允许加载引用,进行文件维护,并支持其他行为。

IntelliJ有个东西叫key prompter,每当你使用菜单进行选择时,一个对话框就会弹出来告诉你可是使用的快捷键,以及你已经做错了多少次。

eclipse也有类似的软件:http://www.mousefeed.com

提示:在一段文本上执行某个特定操作的次数越多,就越有可能会再次重复它。

键盘宏工具:

win下最流行的键盘宏工具是autoHotKey,mac有2个属于“商业的但不贵”的那一类,比如textExpander和Typinator。

运用加速方法有2个条件:对加速器的了解,以及使用它们的适当场景。

第三章 专注法则

排除干扰

隔离策略

对于视觉打扰,应该关掉机器上所有分散注意力的东西。

搜索优于导航

用虚拟桌面拆分工作空间

第四章 自动化法则

做简单重复的事是在浪费注意力。

Categories: Reading Tags:

RESTful Web Services 中文版

September 7th, 2009 cashplk 1 comment

第 1 章 Programmable Web及其分类
1.传统网(human web)返回HTML文档。
2.可编程网(programmable web)返回XML文档。
Amazon S3的作用是“在桶(一种带标签的容器)里存放对象(一种带标签的数据)”。
Programmmable web是基于HTTP和XML技术的。
HTTP:信封里的文档

HTTP是一种基于文档的协议。客户端把文档放在信封里,然后发给服务器,作为回应,服务器把响应文档放在信封里,然后发给客户端。
HTTP响应可分为三个部分:
1.HTTP响应代码(HTTP response code)
2.相应报头(request headers)
3.实体主体(entity-body)或表示(representation)
XPath介绍
利用它,可以方便的将XML文档进行切分。关键的一点是:把XPath表达式看成一种从XML文档里提取标签(tag)或元素(elements)的规则。要知道一个XPath表达式是什么意思,只要从右边往左读就是了。
比如:表达式 //photo 的意思是:
寻找所有photo标签  photo
无论它在文档里何处  //
用REXML::XPath.each(doc,’//photo’)这行简单的Ruby代码可以实现遍历每一个photo标签,而不必遍历整个XML树。
相互竞争的服务架构
REST式、面向资源的架构
REST式架构意味着,方法信息(method info)都在HTTP方法里;面向资源的架构(ROA)意味着,作用域信息(scoping info)都在URI里。
RPC式架构
RPC架构意味着:方法信息和作用域信息都在信封或报头里,至于具体采用哪种信封,并不影响这里的分类。
XML-RPC是最典型的RPC架构的例子,虽然目前XML-RPC主要是一种遗留协议,但由于相对简单,并且容易理解。
REST-RPC混合架构
许多只读的Web服务,尽管他们起初也许是按RPC风格设计的,但都可以称得上是完全REST式和面向资源的。但是,如果该服务允许客户端修改数据的话,就会出现客户端所使用的HTTP方法与真正的方法信息不一致的情况–这样就不具有REST式服务的特征了。这样的服务,称之为REST-RPC服务。
Programmable Web涉及的技术
HTTP
URI:一个REST式面向资源的服务为客户端可能操作的每一则数据暴露一个URI;一个REST-RPC混合服务,为客户端可能进行的每一个操作暴露一个URI;一个RPC服务,为每个处理远程调用的进程暴露一个URI。
XML-RPC:是一种用于表达“函数调用及其返回值”的数据结构格式。专用于RPC式Web服务的。
SOAP:一种基于XML格式的信封格式。现在基于SOAP的服务,其SOAP信封里包含的是一个对RPC调用的描述。
WS-*:这些标准定义各种特定用途的SOAP报头。
WSDL(服务描述语言):用于描述SOAP Web服务的XML词汇。客户端通过参考WSDL文档,可以确切地知道它能够调用那些RPC式方法,这些方法需要哪些参数,以及返回值有什么数据类型。
WADL(Web应用描述语言):用于描述REST式Web服务的XML词汇。
第2章 编写Web服务客户端

Web服务就是网站
XPath讲解
以从右到左的顺序来读 /ResultSet/Result/Title/[]这个表达式,意思是:
寻找直接子节点                             []
谁的直接子节点? Title标签的            Title/
哪里的Title标签?Result标签下的        Result/
那里的Result标签?ResultSet标签下的 ResultSet/
那里的ResultSet标签? 文档根目录的   /
用XML解析器处理响应
XML解析器可以分为三种:
有两种基本额你的XML解析策略,基于文档的(document-based)策略(如DOM等树式解析器)和基于事件的(event-based)策略(如SAX及”拖式“(pull)解析器)。
树式解析器把XML文档建模为一种嵌套的数据结构。DOM解析器是一种树式解析器,它实现了一个W3C定义的接口。
基于文档的树式策略,树式解析器可以把文档视为一个对象,最大的缺点是:必须把整个文档作为整体来处理。
SAX式或拖式解析器把一个XML文档转换成一个事件流,而不是数据结构。首标签(starting tag)、尾标签(closing tag)、XML注释(comments)、及实体声明(entity declaration)等都是事件(event)。假如几乎每个时间都要处理,那拖式解析器是很有用的。拖式解析器允许你一次处理一个事件。
SAX解析器更为复杂,但它在你只关心部分事件时会很有用。可以向SAX解析器注册一些回调方法,一旦定义好回调方法,解析器将按照既定的、跟文档无关的步骤执行下去:解析器将把XML文档转换为一系列事件,并接连处理文档中的每个事件;每当一个事件与回调方法所对应的事件相匹配时,解析器就会触发该回调方法,执行你定义的代码;在回调方法执行结束后,SAX解析器将接着继续处理事件序列。
基于文档的解析器的优点是:可以随机访问文档中的内容,而对于,基于事件的(event-based)解析器,事件触发之后,就没机会再次处理了。
Ruby: REXML
Ruby自带一个标准的XML解析器 — REXML。它同时支持DOM和SAX接口,而且对XPath的支持也很好。遗憾的是,REXML在严格性上处于一种尴尬的位置:它有一定严格性,因此不能指望用它来解析格式有错的XML;但它又没有严格到能拒绝所有格式有错的XML,所以又不能完全信任它的安全性。
如果想确保你只接受良构的XML,需要安装 libxml2库的Ruby语言映射。
如果希望处理格式有错的XML,最佳选择是 hpricot。以 hpricot gem的形式存在,速度比较快,接口比较直观且支持常见的XPath表达式。
第3章 REST式服务有什么特别从不同?
介绍Simple Storge Service
有两个流行的Web服务能满足这一目的,Atom发布协议(Atom Publishing Protocol, APP)和Amaze S3(Simple Storge Service)。
S3主要被用作两种用途:
1,备份服务器
2,数据寄存。
S3 的面向对象设计
    S3基于2个概念:S3桶(bucket)和S3对象(object)。一个对象就是一则附有元数据的具名的(named)数据。一个桶(bucket)就是一个用于容纳对象(object)的具名的(named)容器。桶类似于硬盘上的文件系统,对象就类似于系统里的一个文件。桶只可以包含对象,不可以嵌套,只有通过给对象"directory/subdirectory/file-object"式的命名来模拟实现层次结构。
关于桶:
    每个S3用户只能创建最多100个桶,而且你的桶不能跟其他用户的桶重名。建议要么把所有对象都放在一个桶里,要么用自己的项目名称或域名来给桶命名。
关于对象:
    对象有四个相关部分:
    1,对象所在桶的医用。
    2,对象里的数据。术语称为value。
    3,对象的名称,术语称为key。
    4,与对象关联的一组元数据键-值对(metadata key-value pairs)。主要是自定义的元数据,不过也可以包含ContentType和Content-Dispostion等标准的HTTP报头的值。
假如把S3实现为一个面向对象代码库的话,那么将会有S3Bucker和S3Object这2个类,他们各自均有用于数据成员读写的方法。
资源
    Amazon S3提供了2种Web服务,基于普通HTTP信封的REST式服务(RESTful service)和基于SOAP信封的RPC服务(RPC-style service)。
1,许多RPC式Web服务都是有它们内部的实现方法(implementation methods)自动生成的,他们暴露的服务接口跟它们在内部调用的编程语言接口是一样的。
2,REST方式暴露的是资源,而不是自己命名的函数。资源(resource)响应的不是像getObject这样自己命名的方法,而是响应GET,HEAD,POST,PUT,DELETE和OPTIONS这些标准的HTTP方法。
REST式S3服务提供三种资源,他们(及相应的URI)分别是:
    桶列表(https://s3.amazonaws.com/):这种类型的资源只有一个;
    一个特定的桶(https://s3.amazonaws.com/{name-of-bucket}):这种类型的资源最多有100个。
    某个桶里的一个特定的S3对象(https://s3.amazonaws.com/{name-of-bucket}/{name-of-object}):这种类型的资源数量不限。
前面那个假想的面向对象的S3库里的每个方法,都可以转化为上述三种资源和六种标准方法的某种组合。如下:
每个资源都暴露相同的接口,并以同样的方式工作。如果要获取一个对象的值(value),就向该对象的URI发送GET请求,如果只要获取一个对象的元数据(metedata),就向该对象的URI发送HEAD请求,如果需要创建一个桶,就自己构造一个含有桶名的URI,然后向该URI发送PUT请求;如果要往一个桶里添加对象,就向含有桶名和对象名的URI发送PUT请求;如果要删除一个桶或对象,就向其URI发送DELETE请求。
HTTP响应代码
应该充分利用HTTP本身的响应代码。
如200 OK,404 Not Found,403 Forbidden, 400 Bad Request,409 Confilct。更多的请看 iceskysl的。
XPath讲解
以从右到左的顺序来读 //Bucket/Name这个XPath表达式,它的意思是:
寻找所有Name标签                 Name
那里的Name标签? 直接在Bucket标签下的  Bucket/
那里的Bucket标签?任何地方的           //    

第4章 面向资源的架构

一个具体的REST式架构 — 面向资源的架构(Resource-Oriented-Architecture, ROA)。ROA是一种把实际问题转换成REST式Web服务的方法:她令URI、HTTP和XML具有跟其他Web应用一样的工作方式,令程序员们容易使用它们。
将介绍面向资源的架构的功能成分:资源、资源名称、资源表示、资源间的链接。
可寻址性 Addressability
可寻址的应用可以为每一则信息都提供一个URI。可以将URI发给其他人,缓存或被加入书签。
无状态性  Statelessness
意味着每个HTTP请求都是完全孤立的。
表示 Representations
表示的选择 为一个资源的多个表示添加不同的URL。

链接与连通性 links and Connectedness
统一接口 The Uniform Interface
POST
PUT和POST的区别在于:假如是客户端负责决定新资源采用什么URI,就是用PUT;假如是服务器负责新资源采用什么URI,就用POST。
在REST设计中,通常被用于创建从属资源。
第5章 设计只读的面向资源的服务

资源设计
面向对象程序的标准设计方法是把系统分解成一个个功能部件,即其中的名词。RPC式架构的设计方法是把系统分解成一个个动作,即其中的动词。

根据需求创建只读资源

1,规划数据集

2,把数据集划分为资源

    对于其中的每种资源:

3,用URI为该资源命名

4,设计发给客户端的表示

5,用超链接和表单把该资源与已有资源联系起来

6,考虑有哪些典型的事件经过

7,考虑可能出现哪些错误情况

命名资源

URI设计有三条基本原则:

1,用路径变量(path variables)来表示层次结构(hierarchy)。

2,在路径变量里加上标点符号,以消除误解。当作用域信息的次序有关紧要时,就用逗号。否则就用分号。

3,用查询变量(query variables)来表示算法的输入。

第6章 设计可读写的面向资源的服务

针对上一节的步骤:

添加了2个补充:

4,暴露一个统一接口的子集

5,设计来自客户端的表示

第 7 章 一个服务实现

第11章 将Ajax应用作为REST客户端
Ajax的正式定义:Ajax应用就是在web浏览器里运行的Web服务客户端。
     Ajax应用的不利方面在于,每个应用状态都是同一个URI — 即最终用户访问的第一个URI。这破坏了可寻址性(addressability)和无状态性(statelessness)。虽然幕后的web服务也许是可寻址的和无状态的,但最终用户无法把一个特殊状态加入收藏夹,而且浏览器的后退按钮也失去了原有的作用。
利用 XMLHttpRequest 将XML文档解析成DOM对象,并通过 request.responseXML 来访问该DOM对象。
如何发送请求:
1, 构造一个XMLHttpRequest对象。
例如在Mozilla系列浏览器(例如FF)里,应该是这样的: Request = new  XMLHttpRequest();
2,调用XMLHttpRequest.open方法,并传入跟请求有关的信息,其中前2个参数是可选的:
    request.open([HTTP method], [URI], true, [Basic auth username], [Basic auth password] );
其中第三个参数是用来控制浏览器进行异步操作的。
如果选择异步操作,必须设置一个回调函数:
    request.onReadyStateChange = [Name of handler function];
还可以用 setRequestHeader 方法为请求设置 HTTP 请求报头:
    request.setRequestHeader([Header name], [Header value]);
最后,通过调用 send 方法向 HTTP 服务器发送请求, 如果是 POST 或 PUT 请求,就应当把实体主体作为参数提交给 send 方法。如果是其他请求,就该该参数置为 null。
    request.send([Entity-body]);
如果一切顺利的话,你的回调函数将被调用4次,而且每一次 request.readeyState 都有不同的值。当值等于4时,表明请求已经完成。可以处理响应了。
处理响应:
请求完成时,浏览器会最后一次调用你的回调函数。这时,有以下属性可供 XMLHttpRequest 实例读取。
State属性是数字状态代码。
responseXML 属性里是一个由解析响应文档而得到的 DOM 对象。要求服务器返回XML媒体类型。
responseText 属性里是响应文档的原始文本串。当服务器返回JSON或非XML格式的响应文档时,这个属性比较有用。
可以用getResponseHeader拿到响应包头的值。
Ajax应用可以通过重新实现“后退”与“前进”按钮,来挽回失去的无状态性。但不一定要缺乏创意地模仿浏览器的行为。
跨浏览器问题和Ajax库:
针对不同的浏览器,实例化 XMLHttpRequest的方法是不同的。
以下是Bret Taylor编写的 JavaScript 函数。总是创建一个具有 XMLHttpRequest 功能的对象。 可以在他的网站(http://ajaxcookbook.org)上找到该函数。
function createXMLHttpRequest() {
    if ( typeof XMLHttpRequest != "undefined") {  // typeof 运算符返回一个用来表示表达式的数据类型的字符串。
        return new XMLHttpRequest();
    } else if (typeof  ActiveRequest != "undefined") {
        return new ActiveXObject("Microsoft.XMLHTTP");
    } else {
        throw new Error("XMLHttpRequest not supported");
    }
}
相应的构造方法也该改为 Request = createXMLHttpRequest();
还有2个重要的跨浏览器问题。
首先,Safari浏览器不支持 PUT 和 DELETE方法。如果需要 Safari 能够访问你的服务,就得允许它们用重载的 POST 来模拟 PUT 和 DELETE 请求。
另外,IE会把成功获得的相应长期缓存下来。这样即使资源已经变化,用户也看不到资源的变化。规避此问题的最好方法是:服务器在返回表示时,同时附上适当的 ETag 响应报头,或者干脆用 Cache-Control 报头来禁用缓存。

颠覆浏览器安全模型

Web浏览器遵循这样一条基本规则,即防止来自一个域名的代码向另一个域名发送HTTP请求。可以采用2个方式来绕过此限制:请求代理和JoD。

请求代理:
客户端向 example.com发送请求,在服务端向 yahoo.com 发送那些请求。
Yahoo 文档 ”Proxy for Cross-Domain XMLHttpRequest Calls“详细讲述了这一技术。 在这个技术中,在服务器预留一部分URI空间,用于模拟另一个服务URI空间。当收到一个对应该URI空间的请求时,把该请求转发给那个外部服务器,然后把外部服务器发送你的响应返回给客户端。
JavaScript on Demand:
JoD技术的基本想法是,HTML的 script 标签不一定非得包含写死的JavaScript代码。它可以通过 src 属性来引用位于另一个 URI 的代码。当 Web 浏览器遇到一个 script 标签时,它会加载 src 属性指定的外部脚本,并执行其中的代码。
正常的Web服务客户端可以在调用Web服务后,先查看它返回的表示,如果没有问题再对它进行处理。但假如是客户端提供可执行代码,而Web服务通过特殊手段来自动运行它的话,你就等于对它毫不设防了。
JoD只能发送GET请求。
用 src 属性来引用一个对象,要比用它来获取定制生成的 JavaScript 安全得多。 script 并非唯一可用于让浏览器加载表示的HTML标签。 img 和 frame 标签也可以。
第12章 REST式服务框架
REST 并不是一种架构,而是一种评判架构的方式。面向资源的架构是一种架构,它对设计加以约束,是你能够很容易地把问题划分为一个个REST式资源。
RoR的成功主要在于它的简单化假设。并不是提供了一大堆用以解决问题的工具,只是为你提供了一种用以解决各类常见问题的方式。
资源、控制器和视图
每个Rails控制器可以暴露两种资源。你可以有一个”列表“或”工厂“资源(响应GET和POST请求)和许多”对象“资源(响应GET、PUT和DELETE请求)。
返回的表示
Rails可以根据客户端请求的目标URI或Accept报头决定返回哪个表示。
收到的表示
Rails的工作就是根据收到的表示生成一组关键字-值对,并以params hash 的形式来提供这些关键字-值对。
Rails/ROA 设计步骤
1,规划数据集
2,把数据集分配给一个个控制器
    对于每一个控制器:
    a,该控制器暴露的是一个列表或工厂资源吗?
    b,该控制器暴露的是一组对象资源吗?
    c,该控制器暴露的是一个用于创建或修改资源的表单资源吗?
        对于列表和对象资源:
            设计来自客户端的表示。
            设计返回给客户端的表示。
            把该资源与已有资源联系起来。
            考虑有哪些典型的事件经过?
            考虑可能出现哪些错误情况? 同样,这里常常可以采用基于数据库技术的应用的控制流。
Restlet的思想是 HTTP 客户端与 HTTP 服务端之间的差别,对于架构来说无所谓。一个软件应可以既充当Web客户端又充当Web服务端。
需要注意2点:
1,Web服务器的实际工作是由一个非常紧凑的、基于Simple框架的HTTP服务器连接器来处理的;
2,用强大的db4o 对象数据库来存储领域对象的。
Django的思想是:URI是一个Web应用的用户界面的一个重要部分,不应是自动生成的。Django让你从零开始设计URI。
Django框架的独特风格是:总在URI的末尾加一个斜杠。
urls.py也是采用URI模型的出现次序来依次比较的。和Rails不同的是,Django不用为我判断URI格式。
作为Django视图资源的实现
在Rails中,为了实现一个资源在统一接口幕后的行为,需要把代码放在controller中。 而在Django中,这些代码是放在view里的。

读书笔记:我的成功,你应该复制 — 作者卡梅伦·约翰逊

September 4th, 2009 cashplk No comments

     帮助人们实现财务自由,过上富足的生活,并忠实于自己的价值观和人生目标。鼓励大家掌握自己的职业生涯,并找到让自己真正感到满意和快乐的工作。

我从我的企业家父母身上学到的最重要的东西,或许可以用我爸爸常说的一句话来概括:"如果你在做自己喜欢的事情,那你每天都像在放大假。"

我很幸运,在很小的年纪就学到了一个成功商人需要掌握的关键法则:首先要相信自己。

一直以来,我都在学着相信自己的直觉–这非常关键。你可以从别人那儿学到各式各样的东西,但最终,唯一能够依靠的只有自己的直觉。你的事业的最重要的基础,取决于你自己。

这是每个生意人都应该掌握的基本知识:你不仅是在创办一家公司,还是在创建一个潜在的顾客群,可能在你家所在的社区,可能在互联网上的社群,也可能在一个国际性的社群里。
你必须确定一个核心社群,然后在此基础上扩展开去。
从"笑与泪"获得的经验,还让我学会了另一样重要的东西,那就是口碑的广告效力。其实,我做的所有广告都是通过口耳相传,好口碑总能为我招揽到足够的客源,而且满意的顾客还会向其他人推荐。

我能给你的最重要的建议之一就是,构想一个用最少的现金投资就能起家的生意,并花最少的钱做宣传,如果你是第一次做生意更需如此。

今天,如果我要考虑创建一家全新的公司、进入一个我以前从未接触过的市场时,就会问自己:"这个行业里的人需要些什么?是什么事使他们烦恼、浪费钱、得不到自己想要的东西?"

我认为最有价值的教育,也就是那种在商业上获得成功不可或缺的教育,只会来自一个地方:你自己的经验。我的成就,与其归功于任何一种知识,不如说是来自于以下3个方面:
1.愿意努力学习;
2.坚定贯彻自己的想法;
3.勇于面对失败。

我在魔幻城福特公司学到的最佳管理法则之一就是,忽略小事通常是最好的做法。相反,评价员工时应当以他们为公司所作的贡献以及创造的价值为评判标准。他们为公司的健康发展所作出的贡献,才是你最应该看重的。

cashplk的心路历程 is Digg proof thanks to caching by WP Super Cache