分类
Coding Experience

程序之路上的一些感悟

好久没有写东西了,转眼工作近7年了,趁着有激情,写一写这些年的工作感悟吧。

中心思想,还是围绕着如何走好程序之路,如何积累,如何提高,总结总结,少走弯路,站在前人的肩膀上,越走越远。

一项工作做的越久,就越能感受到工作的平凡。这话是什么意思呢,就是说,刚开始工作靠的是激情、速度,但越到后面,靠的越是方向、耐力。还在坚持的、剩下的人越来越少了。很多人上了年纪就转行了,剩下的人中,一部分也会因为成家了,有小孩了,很多心思和重心会放在孩子身上,追求工作和生活的平衡。所以也是“剩”者为王。就算是工作进取心较强的人,也会由于没有同龄的对手,只剩下自己和自己较劲了,所以,从主客观因素来看,工作是寂寞的,是平凡。

工作的越久,会发现技能、技巧的成分越少。刚毕业时,总能感受到某项新技术的震撼,特别牛。但久了会发现,真正牛逼的是深度,而不是某项技术。技术日新月异,XML之后又有JSON,Java之后又有grovvy, go, nodejs, swift,VMware之后又有docker。HTML5, Java8, Java9,等等。总之,新技术从来没停止过出现。如果只着眼于学习一种牛逼的技术,那么很可能会失望,等技术过气之后发现很无奈。相反,技术深度却永远不会过气,比如高并发架构,高可用,灾备,性能调优,等等,是每个技术都离开的话题。不同技术的差别,只不过不同场景的差别,简单来说就是适合干的事情不同,有牺牲性能提高可扩展性的,有牺牲性能提高开发速度的,但也有只注重性能的场景,根据业务需要,选择不同的技术,有条件可以做搭配,发挥各种技术的长处,扬长避短。

什么都会,其实就是什么也不会,精力被分摊了,或者说,如果你真有一样拿手的,你很难做到,也没必要做到什么都会。在差一个数量级的人的眼里才可能觉得有些人什么都会,其实不是的,人总要从自己身边的事情,工作需要,缘分,先接触到技术做起,而且先要有一门看家本领,所以掌握程度总会有较大差异。

其实就算是开发,也会有分化。有项目做的多的,客户需求,行业知识掌握的多的专家。有专攻通用技术框架,对时间复杂度、算法敏感的技术大牛。个人感觉,程序写多了,其实就是思维习惯的改变,越来越懂如何用程序将现实表达起来,也就是常说的业务建模。不管是行业专家,还是技术大牛,其实也有很多共性,就是持续学习。搞开发就像搞建筑,偏实践,动手能力。所以所谓的牛逼的技术,也许核心就是科研人员的一篇论文,懂实践的人用程序实现了。将精力花在自己擅长的环节,是一种聪明。

设计比编程重要,方向比设计重要,一切目的都是积累。如果谁能用技术将人类的智慧管理起来,每个人都干不同的事,最后大家又能无冲突的汇集起来,那人类就无敌了。其实编程没有难事,一切觉的难都是因为没有想明白,等想明白了也就不急着去做了,反而觉得浪费时间,想明白就是设计。然而技术之路能走多远,兴趣、身体健康状况、寿命长短、心态、正义等等都起决定作用,资源调配的合理才能走的远,有时有必要可以牺牲速度,这就是方向。最后看毕生成就的高度,或者技术的伟大程度就是看积累的总量,所以,哪怕一点点进步,但是坚实的,方向是向前的,都应该为自己庆贺!

洋洋洒洒,又写了这么多。也是最近1、2年来的所见、所思、所想。既然想走的远,总要迈出第一步。希望我的文字,能帮助到别人,值了。

分类
Coding Experience

我是如何坚持地走着技术道路的

PS:经过一段时间的蛰伏,动荡,迎来了短期的心态的平静。趁热打铁,离梦想更进一步。

随想:写代码如同写诗,他是思想的结晶,寄托着你想表达的情感。

我想说,喜爱很容易,坚持不容易。你可能因为兴趣,喜欢上某一件事,你想去做它。但世上少有不需要坚持就能做好的事情,总会有瓶颈,让你感到付出和回报不成比例。或者你尽力了,但效果不理想,很多时候,这种时候的这种想法,会成为我们放弃坚持的理由。

辩证的去思考,容易做的事情,大家都容易,喜悦感来的快,但也走得快。难的东西,大家都难,喜悦感来的慢,来的艰难,来的痛苦,但到来的时候,喜悦更强烈,更喜悦。想想高考,当年是如何挑灯夜战的,是如何坚持每天凌晨2点睡觉的,考完试是如何不悔的,拿到大学通知书是如何喜悦。你可能不够聪明,但更可能不够努力。压抑的越久,快乐到来时来的越强烈。

技术道路或多或少有相似的地方,走的人很多,坚持的人很少。我是如何坚持的?答案很简单,爱好。答案很虚伪,有人说了,好羡慕有人有这种爱好。这种爱好,不是天然的,是一种思辨,一种选择。眼观放长远,收入预期放低些,保持爱好的精神饱满体力放松,就像散步一样,想要走的远,千万不能跑,要健康的走。切记,不要急于求成。保持住这种状态,便会有源源不断的兴趣,源源不断的动力,一直坚持下去。

其实在选择之前,会问为什么,为什么走技术道路。技术是我进入社会的切入点,技术工作充满神秘,有一种敬畏。三观很正,具有常说的一些优点,比如工匠精神,钻研精神,和气,温柔。这样的人,建设出来的祖国,世界,也会充满温柔,关怀,充满爱。

我是本科毕业已经做了6年的技术,对事情初具自己的想法,看法。也具有一定独当一面的实力。其实,技术的职业道路可以说见仁见智,衡量的尺度很多种,不必追求唯一。始终有所收获即可,保持学习,保持成长,是最重要的。被面试过,也面试过别人,被鄙视过,也被抬举过,拒绝过别人。这些都没什么,最重要的是你自己对自己的看法。

其实一路走过来,也并不平坦。第一份工作在国内软件公司100强,写过C++,写过Java,也写过Flex,很杂,可以说公司需要你用什么,就学什么。好在日子过的扎实,项目经验极其丰富,短短4年做的项目、产品不下10个。调侃自己是:没待过互联网,但有些项目加班却加出了互联网的感觉,呵呵。1星期保持通宵状态,为了项目上线,我都挑了一根大梁,成功了。那次经历对我鼓励很大,启发也很大。当时很累,后来成为了宝贵的财富,值了!第二份工作也是现在,在一家刚进世界500强的外企。一切高大上了起来。因为前一段工作积累很扎实,所以第二份工作上手很快,适应很快。挑战都和技术无关了,反而是一些语言、工作方式上面的。研究的技术也前沿了许多,获取新知识的手段和渠道也宽了很多狠毒。夸张点说简直是做梦都会笑,呵呵。工作职能的安排上,也专注了很多,专业了很多,基本上只需要研究专属领域的技术了,不会再有像之前那样大的跨度了。目前一直专注在Java、云方面的技术了。

回头看来,只有坚持着,才会不断收割之前老天欠你的财富,只有眼光放长远,你才能走的更远。像我的经历的坎坷体现在,毕业错过了某大公司,刚毕业做的东西太杂哪一样都时间不够去学好,好不容易精通了Flex,Flex却死了。曾几何时也一度羡慕过混着互联网的同学,感觉身上个个带着光环。保持学习,不放弃,你会了,这事就成了。后来,又精通回去了Java。其实回顾以往工作中,有80%以上知识或技能是自学的,知识还好,其实最重要的是,养成了快速学习的习惯。后来发现,学的快其实才是我的核心竞争力。

当有了一定基础之后,回过头来,再看世界,再看问题,眼光和着重点又不同了。我不再用某一种语言,或者技术去思考,比如Java,之前有一个阶段,我会认为掌握某一种框架是能力,框架能做的事情,我再去做。但今日又有不同,更多是对问题的一种抽象,定义。也是所谓的建模。宏观上,实体定义好,关系定义好,微观上,流程定义好,策略定义好,最后统一考量安全性,高可用性,维护下,扩展性等方面。因为Java是一种最方便实现的语言,它有完善的作用域类型,足以抽象表达出各种业务场景。配合框架实现狠多基础架构的工作,你只需要定义好架构,接口,只需要实现业务逻辑就好。基础框架越完备,业务逻辑就可以越纯粹。

技术一直在发展,推陈出新,比如,时至今日,又热起来的微服务,使用Docker+Spring Boot去实现Java语言的系统重构,相应基础架构管理的Zookeeper+Kafka等技术。所以,仍然要跟上脚步,保持学习。

如果说重复是程序员的魔咒,那么只有不断学习,不断进步,才能始终保持做不同的事,以传帮带的精神,也不断有新人接过你用已掌握的旧的知识做的重复的事情,对于新人也是新的知识,也是新的挑战,这样就是一个健康的生态环境。

最后,再回归主题,说我是如何坚持地走着技术道路的。我想,就是用一种愉快的开放的心态吧,想着要人别人快乐,这样别人最后也会让你快乐。对未知的世界保持好奇,新鲜。保持学习,保持进步。以这样的一种方式去“爱好”。就像写这篇blog的出发点一样,把一种正能量的心态,成果,经验知识分享给更多人。

分类
Coding Experience

小谈关于WADL,ALPS和OData

标题中列举了3个,都实现了RESTFul接口描述的技术,觉得很有趣,想放在一起比较一下。

WADL,是我遇到的第一个,能把REST接口,描述清楚的语法。它是在学习Jersey时,遇到的一个技术,已经是在成为JavaEE标准的roadmap中了。可以参见:https://wadl.java.net。它是基于XML格式,类似WSDL的概念,模仿过来的。

OData,是遇到的第二个,是在工作中遇到的,一片新的天地,绝对强大的新天地。它是基于JSON格式的描述语言,叫做metadata。它不仅规定了DataType,而且还规定了operation类型,更加严格,也更加规范。当然,也缺乏灵活性。

ALPS,是今天才看到的,Spring Data Rest的内容,http://docs.spring.io/spring-data/rest/docs/current/reference/html/#metadata,也有规范作为依靠,https://tools.ietf.org/html/rfc6906。刚刚接触,不太了解,大概浏览了一下,也是基于JSON格式的描述语法。

WADL更像是WSDL的REST版本,是一种补充。OData更像是一种规范的ATOM的Web Resource,有点像Web层的DAO。ALPS更像一种API,类似与REST的Java Doc。

总的来说,语义的自我表述,是一种趋势。引申一步讲,规范,描述比技术,功能或实现,更加重要。我们更希望一个一目了然,一下子知道干什么的工具。其实,也解决了一个程序员的大问题,就是功能和描述不一致。总之,这总,利用技术手段,增强的一致性,才是大势所趋吧。呵呵。

分类
Coding Experience

今天学了点SAP EP系统Web Dynpro工程的迁移

        这两天在本地出差,一个客户系统升级代码迁移过程出了点问题,请了位我司的专家来指导,我跟着来学习。避免遗忘,仅此记录一下。

        迁移是有指导手册的,说的也比较详细了,但现实情况往往更复杂,一般人照着弄,很容易出错。怎么说呢,虽然感觉我不会出那些个错,但毕竟我不是当局者(迷),而是旁观者(清)。归类错误,可分为以下几类:

  1. 没有一个好的例子做参照,不能做对比试验。对于一个陌生的且庞杂的系统,通常应该先基于一个运行良好的基础版本进行改动,而且改动幅度不能太大,一点点的改,遇到错误了,一点点回退,试也能试出来,改了哪导致不行的。该客户的情况是。。。代码管理出了问题,升级前的代码就不work,更何况升级后呢。

  2. 别一下子猜2步。发现客户的开发特别逗,喜欢猜,并且基于自己猜测的结果为前提,又开始第二步猜测,然而第二步猜测往往诡异而奇怪,比如,我看到错误提示日志里面我的模块名的前缀和我定义的不一样,我看到工程属性这个地方有显示,和日志里面的一样,感觉是改这里,但是!这里为什么编辑不了呢?好奇怪。。。我也觉得好奇怪,怎么能往这个方向猜呢。。。最后问题解决了,真正原因是有些更基础的基础包没有迁移。。。

  3. 没有理清原理就开始干,干一点,算一点。怎么说呢,就算我没用过SAP的产品,我用过Java,至少知道jar包之间是有依赖关系的,最底层的包要先部署,要先搞对。否则先搞上层的没有意义。Java里面有maven或gradle,专门解决这个问题。

        下面说说技术相关的经验:

  1. 越是奇怪的问题,导因往往越简单,简单到甚至是可能某个文件没有访问权限。。。

  2. 有顺序,或者依赖关系的事情,千万要按照步骤来,否则出了错都没意义,比如迁移过程,有些东西就要先做,有些后做,别存在侥幸心理,认为只是换了个顺序。

  3. 站在程序的角度想想,就好比让你做这个迁移工具,每一步需要知道什么信息,你是否提供了?否则不可能无中生有,巧妇难为无米之炊。

        综上,其实迁移这个过程可以这么理解,由于JDK版本升级了,以及部分产品接口模块重构了,所以导致旧的代码直接用不了,所以需要迁移,并且有些改动,已经不是工具能自动化完成了。然而Web Dynpro不仅仅是源码,而且还有生成的代码,所以要这么干:

        先把生成的代码清理掉,然后导入到新的工作空间,IDE会自动识别出旧版本的工程,并且提供了迁移按钮,有初始化向导,自动完成迁移,主要是工程配置文件的变更,先搬进新的工程,然后在新的工程下,代码会有错误,首先就是该JDK版本,其次按照指导手册里面的对应关系表,把新旧类改成新类名,等没错了,然后再编译生成新的代码,最后再部署到新系统。完成。

        我喜欢程序的思维,因为程序的思维缜密,有逻辑,而且不会偷懒,不会骗人,让人觉得放心,踏实。

分类
Coding Experience

程序员排错的第六感|老鸟谈经验

    作为一个4年工作经验的程序员,记录与分享下自己的排错经验。

    场景1:

    经常,我们会被派去研究一个新的问题,也许是刚入职不久,师傅让你自己先研究,也许是工作了一段时间,由于工作需要,要研究新的东西。我们常常觉得心里很没有底,感觉好像到处是吭,随便一个小怪就会把自己搞残血,不一会儿,就放弃了。。。

    尤其是刚入职的人来说,貌似被分配了一个很简单的任务,貌似自己研究要花费很久的时间,貌似导师很轻松就能搞定。。。越想自己越弱小,好像一直要给导师暗示出,看,导师你应该给花时间耐心的教我,不要让我自己搞,我搞不定,不然将要花很久。

    大部分时候,导师不会一板一眼的教自己,一副很拽的样子,只告诉你原理,原理往往是那种高大上,也听不懂的,往往不明觉厉东西。然后心里略带委屈的继续默默研究。

    我想说,我经历过新人,也经历过导师,我当新人的时候,是那种拽拽的新人,当导师时是那种弱弱的导师。下面分享我的经验。

    我作为新人,如何做到拽?拽不代表不负责任,不尊重导师,不代表很嚣张的样子,不听话的样子,恰恰相反,对待导师,一定要珍惜和他交流的机会,不轻易交流,一旦交流必有准备,必有自己的见解,必须对自己有提高,不要把导师的问题浪费在小怪身上,以至于大怪到没技能了或CD中。

    首先要听导师分配的任务,要相信,在入门阶段,你不会发现JVM的Bug,不会发现C++编译器的Bug,不会发现操作系统的Bug,唯一的Bug绝对来自你自己的代码,现象越奇怪的问题原因往往越简单,不要认为分号、大小写、申请了释放不释放,等等代码规则是很随意的。如果一个应该很简单的问题Try了半天没试出来,你就要分析下前进的方向了,是不是用错东西了?是不是没有访问权限?(新人的访问权限最低,最容易被坑)

    巧用百度验证,如果你遇到的问题,百度上很少,别人很少遇到,90%就说明你的用法不对,工具用错地方了。等你写多代码了会发现,自己的浅显,越来越不会怀疑环境,怀疑像JDK这种东西。当然,话无绝对,1000分之1的概率你给JDK提了一个Bug,在刚出道的时候成为标准的贡献者,高手在民间!(本人在第三年的时候才去研究开源框架代码的Bug,也是出于项目中出现了性能问题,不得不)

    时间就是财富,导师给你时间去研究,好好利用这个时间培养学习能力,天塌了有导师顶着呢,怕啥!一般公司不会让啥都不会的人上客户那里的,作死行为。。。

    写程序,解决问题前,先不要急着下手,先把思路,解题步骤写下来,用笔和纸就行了,一般写程序就像做生物的对比实验,好多东西都是试出来的,然后才理解的。总结出来的。(得承认,我不是那种思维特敏捷的,给我个再简单的问题,我都要花费分析的过程,但历史证明,我是效率最高的)

    和导师,闻道有先后,术业有专攻,长于己的地方就是好老师,不必尽信师。无私的教自己,要感恩。

    场景2

    比如电脑坏了,或者太慢了,很影响你工作效率,你想好好写代码,piu piu的写,电脑半分钟卡2个字出来,光标一直在转圈圈。。。你决定修电脑!拆开电脑看看,是不是灰多了?线坏了?这是发现自己没有螺丝刀!你准备去买螺丝刀,发现住的地方太高大上了附件没有卖的!只得在京东上买,真要买的时候发现京东账号和密码忘记了!你不记得记在那个邮箱了,要用电脑在邮箱里面搜。。。祸不单行,就这么纠结。比如再遇见买回来螺丝刀发现不够用,还有5角型的,还要再买。。。等等,最后发现灰清了,线插紧了还是慢。。。不得不送修。。。再比如小店还修不好,还要去苹果天才吧修。。。还要预约?怎么样,有点感觉了吧,初衷只是想好好写代码而已,却不得已绕这么大一圈。

    给程序排错的时候也是这样的,在领域经验较少,周围没有人可问的情况下,如何解决问题呢?

    解决这种问题要首先需要的是耐心,其次有这些建议:

    1. 条件允许,2个人一起找错,一个人改,一个人看,我c*o,效率超高,尤其在有个爱喷你的队友陪伴的情况下,更是如此。2个人不是用来扯淡的,因为这种问题最重要的是把我主线,不能扯的太远,要随时可以收敛,1个人研究,既想分支研究的专注,又想随时收敛,简直了,我个人认为是矛盾的,起码这种状态我坚持不了很久。想起了一些务虚的话,往往一些务虚的领导爱说,类似既要xx又要xx,N手抓,N手都要硬(N>3,声明:N=2的时候很合理)。什么好的都要做到,要求员工什么都要会,什么都要精,简直能量不守恒。

    2. 大多数情况,条件不用允许。。。那就多费点时间,做好记录工作,慢慢细心的试,同样,做对比实验,逐一排除问题。要有足够的耐心,搭建单元测试环境。往往搭建环境的时间,要远大于试一次的时间。这么做的目的是为了更快的重复问题。以及真正的理解问题。从根上解决。至于实验怎么设计,这个就不用说了,排除法么。如果B这句话有了,没问题,没有就有问题,说明B是少不了的。

    3. 结果导向解决问题。这点最难做到,因为度不好衡量。我见过不少这样的程序员,想法是好的,但是效率很慢。为何,他习惯弄懂了80%再下手,我觉得研究无人涉及的领域还好,说的过去,如果是有别人会的时候,就没必要了,Java核心卷1、2那么厚呢,深入了解MFC那么厚呢,不可能等你把书看完一遍再来写Java,再来写C++,纯理论的学习人会忘记。找到正确可执行的代码,先认为他是对的,先解决主要矛盾,如算法问题,流程逻辑问题,把边边角角的先忽略,比如工具的使用,配置项的配置,能编、能跑、能打印日志就Ok。界面什么的都不美观都先放放,把接口先定好。

    回归主题,扯得有点远,说说第六感。第六感就是遇到那种很基础,而且很少人遇到的问题时,你会发现8成是自己方向错了,或者某个工具用错了,至少这应该是件很简单的事。尽管前路都没走过,全是新的,但是你仿佛知道该如何选择,或者如何判断自己走错了,耐心与时间,你将走出荆棘,前路一片辉煌。

分类
Coding Experience

【转】理解HTTP幂等性

原文地址:http://www.cnblogs.com/weidagang2046/archive/2011/06/04/2063696.html

这篇文章原文写的非常好,推荐在原文中浏览

原文如下:

Todd.log – a place to keep my thoughts on programming 理解HTTP幂等性

基于HTTP协议的Web API是时下最为流行的一种分布式服务提供方式。无论是在大型互联网应用还是企业级架构中,我们都见到了越来越多的SOA或RESTful的Web API。为什么Web API如此流行呢?我认为很大程度上应归功于简单有效的HTTP协议。HTTP协议是一种分布式的面向资源的网络应用层协议,无论是服务器端提供Web服务,还是客户端消费Web服务都非常简单。再加上浏览器、Javascript、AJAX、JSON以及HTML5等技术和工具的发展,互联网应用架构设计表现出了从传统的PHP、JSP、ASP.NET等服务器端动态网页向Web API + RIA(富互联网应用)过渡的趋势。Web API专注于提供业务服务,RIA专注于用户界面和交互设计,从此两个领域的分工更加明晰。在这种趋势下,Web API设计将成为服务器端程序员的必修课。然而,正如简单的Java语言并不意味着高质量的Java程序,简单的HTTP协议也不意味着高质量的Web API。要想设计出高质量的Web API,还需要深入理解分布式系统及HTTP协议的特性。

幂等性定义

本文所要探讨的正是HTTP协议涉及到的一种重要性质:幂等性(Idempotence)。在HTTP/1.1规范中幂等性的定义是:

Methods can also have the property of “idempotence” in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request. 从定义上看,HTTP方法的幂等性是指一次和多次请求某一个资源应该具有同样的副作用。幂等性属于语义范畴,正如编译器只能帮助检查语法错误一样,HTTP规范也没有办法通过消息格式等语法手段来定义它,这可能是它不太受到重视的原因之一。但实际上,幂等性是分布式系统设计中十分重要的概念,而HTTP的分布式本质也决定了它在HTTP中具有重要地位。

分布式事务 vs 幂等设计

为什么需要幂等性呢?我们先从一个例子说起,假设有一个从账户取钱的远程API(可以是HTTP的,也可以不是),我们暂时用类函数的方式记为:

bool withdraw(account_id, amount) withdraw的语义是从account_id对应的账户中扣除amount数额的钱;如果扣除成功则返回true,账户余额减少amount;如果扣除失败则返回false,账户余额不变。值得注意的是:和本地环境相比,我们不能轻易假设分布式环境的可靠性。一种典型的情况是withdraw请求已经被服务器端正确处理,但服务器端的返回结果由于网络等原因被掉丢了,导致客户端无法得知处理结果。如果是在网页上,一些不恰当的设计可能会使用户认为上一次操作失败了,然后刷新页面,这就导致了withdraw被调用两次,账户也被多扣了一次钱。如图1所示:

non-idempotent

图1

这个问题的解决方案一是采用分布式事务,通过引入支持分布式事务的中间件来保证withdraw功能的事务性。分布式事务的优点是对于调用者很简单,复杂性都交给了中间件来管理。缺点则是一方面架构太重量级,容易被绑在特定的中间件上,不利于异构系统的集成;另一方面分布式事务虽然能保证事务的ACID性质,而但却无法提供性能和可用性的保证。

另一种更轻量级的解决方案是幂等设计。我们可以通过一些技巧把withdraw变成幂等的,比如:

int create_ticket() bool idempotent_withdraw(ticket_id, account_id, amount) create_ticket的语义是获取一个服务器端生成的唯一的处理号ticket_id,它将用于标识后续的操作。idempotent_withdraw和withdraw的区别在于关联了一个ticket_id,一个ticket_id表示的操作至多只会被处理一次,每次调用都将返回第一次调用时的处理结果。这样,idempotent_withdraw就符合幂等性了,客户端就可以放心地多次调用。

基于幂等性的解决方案中一个完整的取钱流程被分解成了两个步骤:1.调用create_ticket()获取ticket_id;2.调用idempotent_withdraw(ticket_id, account_id, amount)。虽然create_ticket不是幂等的,但在这种设计下,它对系统状态的影响可以忽略,加上idempotent_withdraw是幂等的,所以任何一步由于网络等原因失败或超时,客户端都可以重试,直到获得结果。如图2所示:

idempotent

图2

和分布式事务相比,幂等设计的优势在于它的轻量级,容易适应异构环境,以及性能和可用性方面。在某些性能要求比较高的应用,幂等设计往往是唯一的选择。

HTTP的幂等性

HTTP协议本身是一种面向资源的应用层协议,但对HTTP协议的使用实际上存在着两种不同的方式:一种是RESTful的,它把HTTP当成应用层协议,比较忠实地遵守了HTTP协议的各种规定;另一种是SOA的,它并没有完全把HTTP当成应用层协议,而是把HTTP协议作为了传输层协议,然后在HTTP之上建立了自己的应用层协议。本文所讨论的HTTP幂等性主要针对RESTful风格的,不过正如上一节所看到的那样,幂等性并不属于特定的协议,它是分布式系统的一种特性;所以,不论是SOA还是RESTful的Web API设计都应该考虑幂等性。下面将介绍HTTP GET、DELETE、PUT、POST四种主要方法的语义和幂等性。

HTTP GET方法用于获取资源,不应有副作用,所以是幂等的。比如:GET http://www.bank.com/account/123456,不会改变资源的状态,不论调用一次还是N次都没有副作用。请注意,这里强调的是一次和N次具有相同的副作用,而不是每次GET的结果相同。GET http://www.news.com/latest-news这个HTTP请求可能会每次得到不同的结果,但它本身并没有产生任何副作用,因而是满足幂等性的。

HTTP DELETE方法用于删除资源,有副作用,但它应该满足幂等性。比如:DELETE http://www.forum.com/article/4231,调用一次和N次对系统产生的副作用是相同的,即删掉id为4231的帖子;因此,调用者可以多次调用或刷新页面而不必担心引起错误。

比较容易混淆的是HTTP POST和PUT。POST和PUT的区别容易被简单地误认为“POST表示创建资源,PUT表示更新资源”;而实际上,二者均可用于创建资源,更为本质的差别是在幂等性方面。在HTTP规范中对POST和PUT是这样定义的:

The POST method is used to request that the origin server accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line …… If a resource has been created on the origin server, the response SHOULD be 201 (Created) and contain an entity which describes the status of the request and refers to the new resource, and a Location header.

The PUT method requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server. If the Request-URI does not point to an existing resource, and that URI is capable of being defined as a new resource by the requesting user agent, the origin server can create the resource with that URI. POST所对应的URI并非创建的资源本身,而是资源的接收者。比如:POST http://www.forum.com/articles的语义是在http://www.forum.com/articles下创建一篇帖子,HTTP响应中应包含帖子的创建状态以及帖子的URI。两次相同的POST请求会在服务器端创建两份资源,它们具有不同的URI;所以,POST方法不具备幂等性。而PUT所对应的URI是要创建或更新的资源本身。比如:PUT http://www.forum/articles/4231的语义是创建或更新ID为4231的帖子。对同一URI进行多次PUT的副作用和一次PUT是相同的;因此,PUT方法具有幂等性。

在介绍了几种操作的语义和幂等性之后,我们来看看如何通过Web API的形式实现前面所提到的取款功能。很简单,用POST /tickets来实现create_ticket;用PUT /accounts/account_id/ticket_id&amount=xxx来实现idempotent_withdraw。值得注意的是严格来讲amount参数不应该作为URI的一部分,真正的URI应该是/accounts/account_id/ticket_id,而amount应该放在请求的body中。这种模式可以应用于很多场合,比如:论坛网站中防止意外的重复发帖。

总结

上面简单介绍了幂等性的概念,用幂等设计取代分布式事务的方法,以及HTTP主要方法的语义和幂等性特征。其实,如果要追根溯源,幂等性是数学中的一个概念,表达的是N次变换与1次变换的结果相同,有兴趣的读者可以从Wikipedia上进一步了解。

参考

RFC 2616, Hypertext Transfer Protocol — HTTP/1.1, Method Definitions The Importance of Idempotence Stackoverflow – PUT vs POST in REST

分类
Coding Experience

一个优秀的提交应该包含什么?

Hawods:

技术党:

本文由 伯乐在线伯乐在线读者投稿 翻译自 /dev/solita。转载请参见文章末尾处的要求。

 

【感谢@neevek 的热心翻译。如果其他朋友也有不错的原创或译文,可以尝试推荐给伯乐在线。】

首先我们来听一个令人恶心的例子。

你看到问题 F00-123 被解决了。这是关于一个你自己很熟悉的子系统的Bug,所以直觉告诉你造成这个Bug最可能的原因。为了证实你的怀疑,你决定看看这个bug是怎么被解决的。你花了很长时间搜索了整个版本历史,直到把这个bugfix的范围缩小到了4个连续的提交,它们分别的提交信息是:dao小调整(dao tweaks)moarFixes, 还有删除一些调试信息(remove debug stuff)。每个提交的修改集看起来都很大,多达十几个文件的几百处修改。“我艹尼@#$%%^&”,你准备骂娘但还是停住了,没有骂出你脑中那句最难听的粗口。”这个bugfix不应该超过三行代码!”。

上面的例子听起来是不是很熟悉咧?很多开发者仅仅只把版本控制系统当成是一堆文件的备份。这些历史备份除了可以让你取回某个时间点上的文件内容之外,没有任何其他用处。下面这些建议可以帮你把你的版本控制系统从一个备份系统,变成用于沟通和文档编写的一个宝贵的工具。

 

1. 每次提交只做一个修改

如果你在一次提交中修复了F00-123F00-233重构了一个类、界面上添加了一两个按钮、还有把整个项目文件中的tab改成空格,那么基本上没有人能review F00-123的bugfix,只有你自己才知道哪些修改属于那个bugfix的一部分,但是一周以后很可能你自己都忘了。

要是一周以后你发现原来的那个bugfix导致了另外一个更严重的问题那你就完蛋了,你不能使用hg backout或者git revert来撤销你的修改,因为那样会把除了那个bugfix之外的所有修改都撤销掉,也意味着你一周的努力白费了。

上面这种问题的解决办法就是“每次提交只做一个修改”,对于怎么样才算是“一个修改”没有任何硬性或者既定的规则,但如果你能够用一个句子并且不用用到“和”这个字来描述你所做的所有事情,那么你算是做到了。

分布式版本控制系统其中一个很好的功能就是,如果你的工作目录中有很多相互之间没有关联的修改,你可以用它来帮你收拾好你的烂摊子(clean up the mess you’ve made),但是最好别在一开始就搞出一个烂摊子。在你开始修改代码之前,先确定你想干什么和你想怎么做,然后再认真把关注点放在你想修改的那个点上。

在没有想出怎么改进某块代码之前,貌似不太可能去修改那块代码。你发现了bug、看到了一些糟糕的代码、还有一些你很好奇想进一步了解的东西。无论你多么想去做,千万别被转移了注意力。这些发现非常有价值,用一个笔记本或者一个TODO文件把他们写下来(jot them down),在完成当前任务之前不要想去解决那些问题。

这个不仅仅是关于更好地提交。当你沉浸在解决某个编程问题里面的时候,你的头脑充满着关于这个问题的一堆细节,如果这个时候你跳去想一些其他问题,那么你会忘了原来那个问题的细节,再回到原来那个问题需要花一些时间。你需要减少任务切换(minimize task switches)来提高你的工作效率。

当然有些时候你会发现在没有解决某些其他问题之前,你很难完成当前的任务。这个时候最简单的方式就是使用hg shelve或者git stash把你当前还没有完成的修改暂存起来,把两个问题的修改分开,提交那个被依赖的修改,再回到你原来的任务上面去。

 

2. 每次提交要包含完整修改

如果一个修改分布到了几个提交里面,那么这个修改也是很难review的。通常这是因为在同一时间解决太多问题导致的,如果你吃不了那么多,却啃了那么多,那么在你想保存其中的某些修改的时候,你会发现大部分的修改都是未完成的。同一时间关注太多问题会导致最后需要很长时间才能够提交完整的修改。(原文是:Focusing on one task at a time takes you a long way towards committing complete changes. 但我觉得作者的原意应该是:Focusing on too many tasks at a time takes you a long way towards committing complete changes.)

有些修改需要花很长时间,所以如果中间在某个点上你搞错了,重头再来你肯定折腾不起,所以你需要在过程中保存一些中间版本。幸好分布式版本控制系统都允许你保存很多中间版本但是最后只提交一次修改到中心版本库(central repository),你可以提交任意多次的中间版本,在最后使用hg histedit或者git rebase把多次的中间版本合并成一个修改集。

另外一种,也是我个人比较喜欢的方法,因为它把中间版本和永久性的修改版本分开了,这种方法使用Git的index,或者Mercurial Queues中的一个patch来保存最近一次正确的(没有bug的)中间版本,每次你做了新的修改你都更新这个index/patch,如果你犯了个错误,你就可以使用他们恢复你的工作目录了。I like to think of it as a one-slot quicksave for version control.(译注:这句只可意会,我不知道怎么翻。)

 

3. 写好注释,说明你修改了什么

像“修复(Fixes)”、“提交(Commit)”这样的提交信息没包含任何有用的信息。如果别人想看看版本历史,像这样的提交信息只会逼他们去看完所有的代码修改,看代码是很费时费力的。写这样一个简短但表达不清晰的提交信息,可能是省了你一分钟时间,但是却浪费了其他人几个小时。

一个好的提交信息可以让看的人清楚代码的哪一部分被修改了,是怎么被修改的,他们也不需要去看你的代码:

 

SomeClass: use bleh instead of xyzzy in someMethod (fixes FOO-123)

 

 

4. 注释说明为什么做这个修改

假设每次修改代码都有一个很好的理由/原因,但如果这个理由/原因被没有记录下来,那么整个代码库(codebase)将面临以下风险:

  • 其他开发者不明白为什么原代码是那样写的。当他们修改代码的时候,他们可能会引入一些原作者已经发现或者避免的问题。

  • 其他开发者认为原代码那样写肯定是有(好的)原因的,所以最好别动它。他们把这些代码看成是一个黑盒,然后加各种复杂的workaround,避免修改原代码。最后导致这个代码库变得臃肿,代码变得难以看懂。

如果你有足够的理由有必要破坏一个项目的规范或者约定,那一定要把这个理由作为注释写在你的代码里面:

 

- xyzzy(bars); + // Our bars are already sorted, so bleh is much faster than xyzzy + bleh(bars);

 

如果你的代码遵守了规范,并且你的代码没有什么微妙(subtleties)的点需要注意,那就没有必要把你的文档注释写在代码里面。但仍然有必要让人知道为什么新代码优于旧代码(尤其是当新代码引入了一个新问题),所以还是要把原因写在提交信息里面的:

 

SomeClass: Don't flush caches in someMethod The caches are flushed automatically at the end of each request.

 

如果一个修改解决了一个已知问题,确保在提交信息里面带上ticket号(bug追踪系统中的ticket),以便其他开发者在看版本历史的时候能够清楚地知道是在什么情况下做出的这个修改。

 

5. 不要提交被注释掉的代码

我没有办法理解提交被注释掉的代码背后的理论依据,我假设这是为了保存旧代码,以防新代码不能正常工作,但这种做法很莫名其妙,最开始我们使用版本控制系统不就是为了保存旧版本吗?!

为什么要注释掉这些代码?这些代码能运行吗?会正常运行吗?曾正常运行过吗?注释代码是我们应该支持还是摒弃的呢?被注释掉的代码毫无用处,因为每当开发者读到这些被注释的代码,总会冒出一些没有答案的问题,它只会混淆开发者视听,让开发者分心而无法更好专注于有用的代码。

对于提交被注释掉的代码这件事情,只有一个原则,那就是:

分类
Coding Experience

程序员如何成功的假装在很努力的工作

喜欢这个标题~

注:谁都不喜欢和懒货一起共事,Initiative to learn,才是真正的程序员,Besides,时刻需要注意学习的方法~ 并不是越忙越好,越累越好,白天走路,晚上寻路。

技术党:

 

 

本文由“外刊IT评论”网(www.aqee.net)荣誉出品

 

这篇文章要讲的是程序员如何假装在很努力的工作。有两种完全不同的动机会促使一个程序员做这种假装:

第一种,你是个懒货——想不劳而获。如果你是这种人,我和你同事都会鄙视你。你不需要看下面的内容了。这篇文章完全不是为你写的!

图1:适当的带一个眼镜,你可以在会议中闭上眼

 

第二种,你有太多的事情要做,而你需要抽出时间去思考和学习。大多数的公司里,经理们或负责人资管理的人都忽略了程序员是脑力工作者、不是做苦力的。

他们通常会有这样的观点,程序员应该全部上班时间都在努力工作。但是,我们是要思考的人,我们需要时间整理思路,学习新的知识,提高自己,成为一个更好的程序员。

如果你是属于这类人,你需要阅读下面的技巧,它们能帮助你从繁重的工作中偷出思考和学习的时间。

努力工作,给人一个良好的第一印象

这个听起来似乎是让人不解。这句话中最关键的一个词是第一印象。假设你新加入到一个团队,你的老板和你的同事将会对你第一天或第一周的表现有个评价,大概感觉出你是一个什么样的程序员。

你给人的这种主观印象越好,往后的几个月甚至几年里你就会有更多的自由。一开始就努力工作,显示你的优秀技术水平,这绝对是会获得丰厚回报的付出。如果能在你的蠢老板或同事遇到无法解决的问题时出手相救,那是再好不过了。

在团队中不要太冒尖

要小心,不要在团队中显得太优异,适当低调。你可以显示出开发速度很快,但不能太快。老板会很快的习惯你的工作效率,会给你安排越来越多的工作。

这种做法看起来和你的初衷背道而驰,你希望能有更多的空余时间做更重要的事,但事与愿违,所以要有策略。而且这样做也避免了让你的同事显得太蠢、太慢。所以,不要干的太快,但要干好,要按时完成。

让代码很好维护

你应该写出最优秀的代码,让代码维护起来很容易。在一项工作上你干的时间越长,代码可维护性将越严重的影响你的个人工作效率。

不要忘了,“任何花在调试bug上时间都是浪费掉的时间!”代码中的bug会让你实现新功能的速度变得越来越慢,你的压力会越来越大。好的设计和写一些简单文档都会日后节省你的时间。自动化你的日常重复工作。写自动化测试。

创造良好的人际网络

善于从别人那吸取知识。你的人际关系越好,你遇到问题时解决方法就越多。公司常规的工作流程只是为普通问题准备的。

当遇到棘手的问题时,你需要有人来帮助你。如果别人不喜欢跟你一起工作,他们就不会帮助你。所以,平时多取悦一下周围的人是十分重要的。

总结

还有很多其它十分有用的技巧能让你从繁忙的工作中获得更多的自由。但最重要的一条是:一旦工作,那就要努力的干,聪明的干,快速的干——用省下来的时间干自己喜欢干的事情。

记住,你的知识越丰富,你就能越好的解决问题/创造价值。我们是脑力劳动者。我们提高个人的能力,公司也会因此受益。

 

 

[英文原文:How to Successfully Pretend to Work Hard as Software Developer? ]

 

 

分类
Coding Experience

可能我们只需要一个能用的程序

常常想着设计出完美的架构,程序足够灵活,动态可配,满足任何变化,想着想着就逐渐脱离了现实,而且往往没有时间与精力去做完。
满足当前需求,才是软件价值所在,我们只需要领先用户半步,可能我们只需要一个能用的软件。

分类
Coding Experience

如何漂亮地问问题

在问之前:

  1. 试着在你要发帖的论坛找已有的答案;

  2. 试着在谷歌或者百度一下;

  3. 试着阅读相关技术的手册;

  4. 试着阅读一下相关技术的FAQ;

  5. 试着猜测一下或者做个实验;

  6. 试着问一个技术牛B的好朋友;

  7. 如果是程序员的话,试着阅读下源码。

无意间看到的,觉得好,分享下~

原文地址How To Ask Questions The Smart Way