请停止结对编程

(根据真实事件改编,情节有所夸张,请勿对号入座。)

这是一个风和日丽的星期五下午,Ben和Martin本应该在Costa咖啡馆喝一杯下午茶,一起聊聊周末的计划,然而PM的一个微信通知打乱了这一切。原来产品出现了一个bug需要紧急修复,下班之前必须要搞定。两人收到消息疾步走回到岗位,也没了心情去喝刚泡好的咖啡,连忙打开邮箱查看问题报告。

开始

Ben:看来这不是一个很大的问题,就是处理一个来自于远端服务的异常。现在的情况是BFF(backend for frontends)在内部的远端服务有异常,会将异常直接返回到客户端,这样只要一个保单出了问题,前端所有的保单也都没法用了。

Martin:那怎么解决?

Ben:感觉可以在异常的地方加一个异常处理。这个涉及到RxJava和Java8的stream特性,我不是太熟悉,要不我们一起Pair吧

Martin:好。

两人喝了一口炙热的咖啡,摆好键盘鼠标,打开了IntelliJ工程。几分钟后,这个故障重现了。

Martin:可以重现的故障通常比较好解决。我们在这里先弄个try…catch试试。 两人似乎很有信心,然而重启项目后,故障并没有按照预期停下来。

Ben:hmm,这里为什么停不下来呢?

Martin:可能是RxJava的延迟处理,没有正确的捕捉到。这样,你在这里再写一个逻辑,然后在这里设个断点……

焦急

在这个过程中,Martin只是对着屏幕指指点点,时不时看看手机、在微信上聊聊天。Ben对RxJava并不是很熟悉,他想紧紧跟随Martin的思路,然而增加多个逻辑以后,依然都不能解决问题。15分钟已经过去,Ben这时候心生怀疑,是不是哪些地方没弄对?

Ben:我们理一下思路看看?

Martin:恩,来吧,一起看一下代码。

Martin领着Ben一起看了一下代码,并且一直在旁边指点Ben进行单步调试。由于RxJava的延迟特性,使得断点很难设置。而抛出异常的调用栈会出现在某些莫名其妙的地方,这让他们根本不知道把try…catch放在哪里才能奏效。

Ben:可能是要这样,在这里加一个OnError看能不能解决。

看似问题能够解决,其实是又一次的失败。在两人的激烈讨论中,时间过得很快,一晃眼已经是1个小时以后,咖啡早已经凉了,然而两个人完全没有心情,甚至都忘了咖啡的存在。

Ben对Martin的解决方案越来越没有信心,两人开始重新讨论起解决方案。然而方案是越讨论越复杂,看起来想在下班前解决这个问题是不可能了,通宵是必然了。

简化

Zen是组里的Tech Lead,今天在忙另外一个事情。这个周五真是不得安宁,恨不得想到美国去过过昨天。

Zen听到两个人的讨论,虽然并不了解这个问题的细节,但直觉上认为是跑偏了。马上提醒Ben和Martin:

这不是一个很难的问题,我感觉你们想复杂了?是不是走偏了?能给我说一下你们怎么想的么?

被Zen打断的Martin说了一下之前的解决方案,也说试过了其他的方案了,都不行。由于Zen对这个事情也不是很了解,所以只是提了一个醒:

“Keep it simple,别把事情整复杂了。”

两个人的讨论依然在继续,Ben有点无法跟上Martin的思路,艰难地写着代码,但每次都不对。Pair的气氛犹如冬日里冰冷的咖啡一样凝结,不知道孰是孰非。Ben已经有些不高兴,Martin则依然在一旁指指点点但并不动手。

Zen一看表已经3点钟了,又插了一句嘴:

Martin,既然你对这个更熟悉,你来操刀吧。你来写代码吧。

可能由于之前的讨论过于激烈,Martin反驳Zen:

我们在Pair啊,他对RxJava不熟悉,我应该指导他。我看着他写就可以了。

Zen说,

你们的解决方案是什么,给我看看。

解释了一通以后,Zen也没有更多的想法,就让他们继续吧。但Zen建议道:

在这个紧要的关头,我们应该改变一下Pair的方式。现在不是教授知识,而是要高效的解决问题。在这种压力的情境下,你可以直接实现自己的思路,带着别人飞就好了。

分歧

Martin稍微冷静了下,拿过键盘,继续开始修复问题。Ben这时候在一旁观察,也适当的休息一下,之前手忙脚乱的按F8、F9的神经也得以缓和。

Ben:看来还是不行。我们再理一下代码吧。

Martin:你说的这些我之前都试过,都不行,要这样才行。

Ben:我说的是这样做的,既然我们还没讨论清楚,我们再来看一下代码吧。

两人拿出了纸和笔,对着屏幕一边画一边讨论,然而Ben并不认可Martin的方案,说要采用另外个方案。Martin则坚持认为这是一个可行的方案,得试试。Ben拿过键盘,准备按照Martin的方案写代码,但心里面颇为不爽,一直在想说服Martin采用他的方案试试。

怒气

到此时,时间都已经不知不觉过去两个小时了,然而问题似乎离真相总是忽远忽近。两个人已经疲劳不堪,再加上解决方案的不一致,两人的言语中开始显露出一些怒气。

Zen在运行测试的空档,打断了两人的对话,建议道:

既然大家已经产生了分歧,要不然两个人分开,各自实现一个,看谁能够先实现,然后再来讨论。

Martin对于Zen并不认同,认为Zen指责他和Ben没有Pair好。

Zen解释道:

其实我听出了两人意见的不统一,言语中已经有一些怒火,这样下去Pair的效率很低。首先,大家带着不爽来干活,互相质疑。更关键的是,解决问题已经用去了两个多小时,大家都比较疲惫,可以适当休息。我让你们分开的目的是让大家冷静一下,在不受打扰的情况下工作一段时间,可能会不一样。

冷静

Martin回到了电脑面前,按照他的思路一步一步做下去。Ben去上了个厕所,倒掉了那杯冷冰冰的咖啡,泡了杯热茶。回到电脑前专注的重新按照他的思路一步一步走下去。

其实两个人已经接近了真相,只是这之间不停的对话把注意力消耗殆尽。两人企图达到一个统一,然而口头的对话并不能解决问题,反而暂缓了这个过程。

10分钟后,Ben兴高采烈的说已经搞出来了一套可以运行的方案,叫Martin一同过来看看。Ben的临时解决方案比较简单好理解,但并不完美。熟悉RxJava的Martin指出了一些可以改进的地方。

然后两人又开始了新一轮的Pair,重新将这个方案完善。有了这个基础的解决方案,两人都很高兴,是朝着一个正确的方向大步向前。

尾声

下午6点半,虽然比正常下班晚了半个多小时,但还好整个解决方案都正常了,交付的任务也顺利完成。

Ben和Martin都总结道,我们应该停止结对,当:

  • 两人的思路不统一但无法说服对方时:我们可以考虑分开一阵,安静一下,各自用可运行的代码来证明思路的可行。这里只需要相对粗糙的代码即可。
  • 时间已经超过番茄时间而感到疲惫时:人的专注力是有限的,在Pair时非常累,特别是在能力方面存在较大差距的时候。在这时候我们可以试试番茄工作法,让大脑得到休息。
  • 注意力不集中或者有其他事务要处理时:在Pair的时候,彼此要尊重对方,不要玩手机、看其他无关的网页,除非事先取得别人的同意,否则就要等到停止结对、处理完事务后再继续。

更多精彩洞见,请关注微信公众号:思特沃克

Share

Bahmni,公开的敏捷项目

Bahmni是什么

在ThoughtWorks,我们有三个重要的使命,其中第三个支柱“推进社会和经济公正”让我们有机会去改变这个世界,让更多的需要帮助的人得到信息化技术的帮助以改善生活。Bahmni(读作“巴姆尼”)正是在这个使命下孕育的一个项目,其目标是让Jan Swasthya Sahyog(人民健康扶助团,简称“JSS”)、以及其它成千上万类似的医院实现信息化。

ThoughtWorks印度公司从2013年开始做这个产品,其核心是一个开源的电子病历(Electronic Medical Record)系统OpenMRS。这个软件内建了一套标准的医疗信息记录数据体系,在北美和南美的一些医院里应用并收到了很好的反馈,并且有一个活跃的社区(包括医学专家、公共卫生专家和IT专家)在不断完善它。我们组建了70余人的团队,分布在印度的4个城市和中国的成都以便支持整个项目的开发。(部分摘自《印度儿童诗雅拉尔之死》)

Bahmni产品目前在印度、不丹、孟加拉国等国家均有实施,最为耀眼的是在孟加拉国,Bahmni会作为整个国家的HIE(Health Information System 医疗信息化系统)。

更多的介绍请见:

我们的敏捷实践

Bahmni是一个开放的敏捷项目,世界上任何一个人都可以对该项目做贡献,而不仅仅局限于ThoughtWorks内部。为了能够让更多的人参与,ThoughtWorks选择了开源的工具、开放的敏捷管理方式,这些管理、实践、工具和ThougtWorks的其他内部项目和客户项目均类似,参与者参能够用到最佳的敏捷开发方法。

公开的知识管理

一款开源的产品如果无法很方便的使用,则失去了它大部分的价值。在Bahmni项目中,团队很重视文档,采用AtlassianWiki进行知识管理。Wiki涵盖了产品的特性、社区、实施指南、开发指南、项目管理等方方面面。ThougtWorks内部对文档进行了持续的更新,保证文档的健全,为项目的参与人员提供了最大程度的便利。

公开的需求管理

在Bahmni项目中,客户是医院的工作人员,他们会提出各种各样的比较模糊的需求。同样在技术上Bahmni也会有自身的一些需求。Bahmni在管理这些需求的时候,采用了Trello将所有的需求管理起来,所有人都有权利看到并对需求提出自己的看法。每过一段时间,产品经理将会对所有的需求进行Review,包括对需求澄清、进行进行优先级的划分。

每一年,Bahmni团队会召开一系列的会议对Trello内的需求进行梳理,制定出一年的Roadmap。所有的人包括来自于OpenMRS的开发者、自由开发人员都可以参加Roadmap的制定过程,提出自己的意见和建议。但这个Roadmap并不是一成不变,敏捷总是拥抱变化,所以在变化产生的时候,Roadmap也会做及时的调整。

公开的迭代管理

迭代计划会根据Roadmap进行制定,我们使用mingle对项目进行迭代管理。

使用这套系统,任何人都可以看到卡的状态及内容,持续跟踪整个项目的进度。开发的人员提交的代码会和卡根据提交记录中的编号进行关联,方便事后对卡片的内容进行追踪。每个迭代都会有一系列的会议,对于ThoughtWorks之外的团队、个人,我们提供了Events Calendar以便他们参加会议。

技术实践

Bahmni项目使用了多种技术实践来保证产品的质量。

我们使用TDD,为每一个业务价值书写单元测试,测试覆盖率高于80%。我们用Gauge对页面进行端到端的测试,每天进行产品的回归测试。我们用GoCD对产品进行持续集成及版本发布,保证发布管理的自动化,减少人工干预导致的各种问题。产品发布并部署到到测试使用的云环境以及Demo环境,全程只需要很少的界面点击即可完成。

活跃的社区

Bahmni是基于OpenMRS的一套医疗管理系统。基于OpenMRS的客户群,我们在OpenMRS Talk中专门开辟了Bahmni的版块,对Bahmni相关问题进行解答。我们深知活跃的社区对于一款开源产品的重要性,所以团队内部有专职的人员对社区进行追踪,尽最大可能及时的回答用户的问题。为了更好的帮助用户快速入门,我们还准备了Youtube的频道进行了大量的讲解。

同时,我们还有IRC Channel对用户进行实时的帮助。Bahmni团队所有的开发人员都被鼓励去回答用户的问题,只有开发人员和用户有最近的距离的时候,开发人员才能理解用户的需求以及诉求,从而设计更好的系统。

我们也积极参与OpenMRS的开发和讨论,每周OpenMRS都会有开发人员的会议,基于OpenMRS的产品团队、开发人员都可以参与到会上进行交流。每年OpenMRS都会举行OpenMRS Summit,Bahmni作为其发布版也参与到其中贡献数个话题并寻求积极的反馈。

总结

Bahmni项目的公开运作方式从产品的设计到需求的获取到最后的开发得到了大量的社区用户的积极参与,线上线下的结合拉近了和用户的距离。ThoughtWorks一项以技术实践为骄傲的敏捷开发方式在产品的生命周期内展现的淋漓尽致,可以说是敏捷项目的一个标杆。


更多精彩洞见,请关注微信公众号:思特沃克

Share

再看API设计——从黑客的角度

互联网的高速发展以及多终端设备的广泛使用使得前后端分离架构变成了必须,越来越多的网络应用暴露出API以便于前端的使用,RESTFul API的设计成为了业界主流的设计范式。在持续的业务增长以及后端技术的革新中,微服务架构(Microservice)崭露头角,解决了单体应用(Monolithic Application)的诸多问题而越来越流行。现在,在客户端与服务、服务与服务之间,有更多的数据通过常用的json等结构化的方式进行交互。这些交互过程在单体应用中对外并不可见,但在微服务架构下对于却变得透明,黑客可以通过窥探及猜测系统内部的结构,会比以前更容易攻击系统。在这篇文章中,我将以一个数据黑客的角度,展示如何利用API来大规模的获取所要的信息。

数据黑客

数据黑客没有一个准确的定义,在我看来这帮人对于数据具有敏锐的嗅觉;他们尝试得到一切能够获得的数据并进行数据分析;他们尝试在数据的云海中找出规律以便预测未来。在程序员拯救世界的今天,数据黑客则掌握了世界的未来。

在若干年前,前后端分离的架构还尚未普及,很多数据的呈现方式都是直接在页面中打印出来,为了解析数据,数据黑客们使用XPATH去解析数据,将数据装入数据库进行分析,甚至从中赚钱。如今,我们有着大量的API供使用,数据变得唾手可得。我们不用再去繁琐的解析易变的HTML,只需要访问一个URL即可获得我们需要的数据。

10天内获得自由职业网站8百万项目数据

我对自由职业充满了好奇,想试一下自由职业是怎么接到活的。在Freelancer网站上,几乎每分钟都有新的项目发布,一般一分钟之内就有好几个投标信息(bid)。每个投标信息包含了投标的内容、价格以及完成时间,然后雇主根据这些信息来筛选谁可能接这个项目。一般来讲会在交谈之后,明确所有的事宜后,再将项目分配给自由职业者。

作为自由职业者,我们可以看到其他人投标的价格以及别人的信誉度、别人做过的项目等信息,但不能看到具体的投标内容。作为雇主,价格、自由职业者的信誉度、是否通过一些测试可能都是影响雇主是否第一轮筛选进行交谈。那么,通过数据分析,能否回答以下几个问题以便帮助我们正确的投标:

  • 针对投标信息,雇主对自由职业者的信誉度和价格,哪个看得更重?
  • 针对澳洲的雇主,我如何能够增加我被选中的几率,是通过降低价格还是提升自己的质量?

为了回答这些问题,我需要尽快的将网站上所有可能拿到的信息都拿下来进行分析。

网站及API分析

打开一个项目页面(注:你需要翻墙),你会看到页面如图所示:

1

 

 

简单的看一下HTML后,发现网站将所有的信息都内嵌到HTML中的一个script中,在浏览器执行完成后会得到project变量。这个变量包含了项目的所有信息,所以理论上讲,我们拿到一个HTML然后解析Javascript,是可以得到我们需要的数据的。

2

 

 

但这种方式也存在一些问题,一来是解析HTML非常费事,二来是执行Javascript也比较繁琐。并且没有一个办法能够遍历所有的项目,可行性并不大。

通常来讲,我不会去解析主网站,因为其防范一般比较严。但很多网站的马奇诺防线在移动端就失效了,Freelancer也不例外。

打开移动端的网页。简单看一下可以知道它是基于AngularJS写的网站。

3

 

 

通过分析API的请求,可以很快的看到API的样子:

4

 

 

我们来分析一下这个URL,红色部分代表了这个项目的简写名字,将其改为其他的项目名称以后能够得到对应的信息。

5

 

 

理论上我只要得到所有项目的简写名字,再用这个地址就可以获得所有的信息了。但且慢,我注意到了投标信息的API:

7

 

 

红色部分用的是一串数字,如果你了解RESTFul API,则很容易知道这个bids的信息是属于9844976项目的。将之前的projects后面的名字变为数字,果然返回ID为9844976的项目的信息,和用简写名字同样的效果。这样的话我就确定了网站每个项目的ID是可以直接访问的,从0开始遍历这个ID即可得到所有网站的信息。

9

 

 

 

阻力:API访问速度限制

当爬到1000个左右的时候,网站就报告API Rate Limit限制了,大概需要一个小时左右才能再次访问。作为一个大型的网站,API访问速度限制是很平常的事情。如果照这个速度访问,则爬完所有的信息需要将近一年。能不能更快呢?

通过匿名代理可以让访问的服务器无法识别出您的真实的IP地址,所以如果有大量的匿名代理,就可以满足爬虫的需求。但这个网站使用的是HTTPS,要找到大量稳定的HTTPS代理需要较高的代价,网络上常见的匿名代理网站提供的代理通常都不稳定。

10

 

 

那么,有没有一个更廉价的方式能够获得更多的IP地址呢?洋葱网络为我们提供可以非常好的途径来隐藏自己的真实身份,并能够得到大量稳定的IP,并且能够在达到API Rate Limit之前就更新IP地址,非常符合我们的要求。

11

 

 

为了让多线程并行,我在DigitalOcean的5美元的服务器上用Docker启动了10个Tor的客户端,这样每个客户端就拥有一个独立的IP,并且每10秒钟切换一次。脚本连续运行10天后,所有的数据全部到达本地。

从黑客的角度看

好的几点:

  • 该网站提供了移动端的API。
  • 有API的限速。

需要改进的有:

  • ID号可遍历:通过将ID变为UUID,可以解决资源被遍历的问题。但这个要视业务场景来定,如果业务上并没有需要保护数据,则简单的ID也是一种选择。
  • 加载的数据包含了很多额外的信息,造成一些信息泄露:在返回的数据中包含了大量的其他信息,黑客可以利用此信息得到页面上没有显示的信息。例如网站上对投标者对雇主的id、用户名等信息是不知道的,但API返回的数据中却有这些信息。这样黑客可以通过这些信息通过其他渠道联系上雇主。
  • 保护网站遭受匿名网络攻击:根据业务的不同,可以设置针对地域的IP限制。例如如果网站大部分针对澳洲客户,则澳洲客户的API使用量可以设置为1千/小时,而其他国家则设置为100个/小时,并且在适当时候显示验证码。

    12

 

获得一年中6亿的机票数据

由于家庭的需要,我会在节假日往返成都和广州,而我想买到最便宜的机票。那么问题在于,我需要提前多少天才能买到足够便宜的机票呢?在我得到数据之前,我曾手工的看机票的数据,但很难发现规律,往往意识到涨价的时候,已经比最低值高出了很多。如果我能持续的抓取每天看到的30天之内的机票的数据,并用于一年后的数据分析,我是否能够找到一些规律呢?

为了完成这个任务,从2012年开始,我开始从各大机票售卖网站抓取机票信息。这里想举一个从某网站中获取机票的例子来看看我们能够从中学到一些什么。

我之前说过从主站入手往往很难攻破,所以直接打开移动的网站:

13

 

 

只需要看一下网络的请求就可以很方便的定位到获取机票的API以及返回值:

14

 

 

API分析 来我们看看API中包含了些什么:

data=%7B%22searchType%22%3A%……

这部分应该是存储的数据,很简单,我们通过decodeURI即可得到可见的信息:

15

 

 

后面一部分是固定的串,有API的key以及版本信息

useNative=true&ttid=201300@travel_h5_3.1.0&appKey=12574478

对于爬虫来讲,最麻烦的部分在于:

t=1426062775998&sign=3feb52aed67967a2c47aa7a2b9f2a417

16

这部分一直在变,并且若干秒后会失效。sign的计算和cookie中的_m_h5_tk有很大的关系,并且每次服务器要返回新的_m_h5_tk的token用于下一次请求。所以如果要生成这个url,必须要将他的计算规律搞清楚。对手前端的加密来讲,基本上如果了解js的开发,能够较快的找出来。首先搜索API中包含的字符串h5apiUpdate,很容易就定位到这里:

17

 

 

但这部分代码已经被压缩,无法打断点。Chrome提供了一个非常棒的代码格式化工具可以方便的将代码格式化为可读性很好的代码:

18

19

 

 

 

再在这里打上断点,所有的秘密都呈现在了眼前:

20

21

 

 

 

剩下的事情就是将这个写成脚本即可,请参考后记。

总结

从这个例子中我们学到了什么:

  • 可以用时间作为token来生成动态的url
  • 用sign去检查请求是否合法
  • 服务端可以用时间token来拒绝重发的请求
  • JS端的压缩可以较为容易的破解

后记

以上的代码我都分享在我的github账号。仅用于学习用途,请勿用于恶意攻击。

  • 关于爬Freelancer那的代码
  • 机票爬取的部分代码。由于网站已经升级,反爬措施变得比较难于琢磨,所以这段代码已经无法正常运行了,仅供参考。
  • 还有1分钟启动10个tor的代码

后来我发现Freelancer网站有一个隐藏的API接口文档,在这个文档中还有更多的信息可以参考。另外知乎上也有一些反爬虫的一些讨论,挺有趣,可以参考

Share

微服务——大企业是如何在实践微服务中成长的

我足够“高”了么?

Martin Fowler描述过当组织在考虑实现微服务架构时,必须要有的一组“能力基线”,但大企业通常有各种理由不太愿意去尝试和成长以达到这样的能力。有很多的文字都提到,在成长之路完成后便能收获微服务架构所能带来的各种好处。这篇文章将描述一个大企业为达到Martin Fowler的能力基线,所经历的挑战和决心。

01
Image by Fabio Pereira

开篇

在行业中,微服务有着众多不同的定义。某些定义认为它是一种和Unix编程风格类似,以构建很多能够专注于做好一件事情的、微小的、有自治进程的架构风格。某些定义认为它是第一个后DevOps革命的架构。它从DevOps和持续交付中吸取到所有的经验,并且对其进行了优化。

我们采用微服务的初衷是为了提供一种能够扩大团队规模的途径。我们从一个单体应用开始,康威定律启迪我们分解这个单体应用。经过这个过程,我们最终变成了很多小而优的团队来进行交付。

团队的结构影响着系统的架构并不是一个新鲜事了。Nygard总结得很到位——“团队的工作分配方式就是架构的初稿”。这种最初对团队伸缩性的需求是将一批最佳实践带入微服务和持续集成的催化剂。

团队的工作分配方式就是架构的初稿。

拆分单体应用

当我们拆分单体应用时,我们面临的第一个挑战是尝试找到系统的接缝或者界限上下文。这种尝试带来了一个非常有意思的副作用,即我们可以通过识别系统中那些比起其他地方更不容易变化的地方,来解耦我们的系统。这和重构代码以让你的代码更经得起时间的考验类似,只不过是在架构层次上罢了。

从单体应用中分割出多个服务是很不简单的。包括创建单独的代码仓库,构建管道和基础设施建设。这些都要消耗时间。因为很多企业都对频繁构建新服务持悲观的态度,我们经常会听到犹豫之声:“如果构建一个服务都用了这么多时间,我们怎么做其他的服务呢?”

我们是在每个迭代中逐步攻克这个问题的。我们改进我们的构建管道、工程的创建、环境设置和部署。这是从微服务架构中所获得的很大一部分益处——它不仅强制性的将质量和成熟度构建进你的软件,而且也包含了开发流程和实践。

步入云端

在改进DevOps最佳实践的路上,配置环境成了畔脚石。如果需要另一个部门花几周的时间,去配置好一个新的机器来托管你的新服务,你就有麻烦了。幸运的是我们已经准备好步入云端,并且已经在企业层面上准备好了支持云部署所必须的工具链。

即便有这些工具,开发人员也必须开始拥有他们的软件,包括生产环境的部署和支持。封闭的组织有一个趋势是将他们的开发人员与真实地生产环境隔离开。“谁构建,谁拥有”这个思想非常的重要,它能促进最佳实践地成熟。亦即,如果开发人员已经对生产环境的稳定性和支持有浓厚的兴趣,那么很有可能是他们构建了这个系统。

谁构建,谁拥有

消费者驱动的契约测试

我们已经拥有了很多已经部署到云端的RESTFul API,并且由团队自己维护这些API。这就意味着团队可以不借助其他人的力量进行独立的开发。不过,我们开始发现依赖的服务在逐渐改变我们的行为。测试和利益相关者开始抱怨系统不稳定——但当我们是单体应用时这根本不是问题。

我们使用集成测试来解决这个问题。服务提供者为其API的消费者维护一组测试,而不是消费者自己为契约写集成测试。这样做有很多的好处:首先,如果服务提供者破坏了契约,它会直接被告知;另外,如果消费者增加了新的测试场景,但这个场景破坏了契约,那么构建也同样会失败。这些考量驱动出更重要的事情,也即团队之间的交流以及尽快的开始这些对话。API始终可以进化,但它会有足够的约束来保证稳定性。

蝴蝶效应

解耦单体应用的另一个副作用是监控的工作量成倍增加。之前你可能在一个应用中只有一个终端(endpoint),而现在你有很多的服务。为了更好地保证应用正常工作,你必须要为支撑你的服务的基础设置上提供足够的监控。

在单体应用中,如果一个服务调用失败了,我们会清楚地知道哪里出错了。但在一个经常变化的解耦架构中不再成立。当一个服务失败了,真实的失败位置可能是在依赖树上的数个服务。这就意味着平均修复时间(MTTR)会受影响——我们必须要调查受影响的服务,也会调查这个服务所有的依赖。我们使用PRTG监控工具来解决这个问题。PRTG给我们提供了一个高级的仪表盘(dashboard)来图形化系统的不同的部件。

我们发现的另外一种必要地监控是分布式的日志收集。这允许我们从不同的服务器收集日志并且可以做联合查询。我们甚至可以引入相关性ID来改进它。这样分布式的日志允许我们跟踪一个请求的在系统的不同服务中的跳转过程。

展望

当然我们还有一些需要在未来解决的困难问题。包括一些棘手的组织变化,例如将交付与产品对齐而不是和工程对齐,并且使开发人员能够在DevOps的环境中工作。这也包含了更多的环境配置,包括更多的通过Ansible来进行基础设施自动化。尽管还有未来的挑战,我们已经开始收获一些引入微服务先决条件所带来的好处了。你的微服务的旅程是怎样的呢?

Share

3D打印的各种问题及解决方案

3dprinting

3D打印机已经买回来几个月了,基本上每天都要打印一些东西,期间遇到了很多的问题积累了很多的经验。虽然现在桌面级的3D打印也算是比较简单好用了,但要追求好一点的打印质量,还是得折腾。

打印校准

打印机的校准包括X、Y、Z和A、B(就是喷头)两个轴的校准。最重要的是XYAB,因为他们直接关系到打印的尺寸大小及表面质量。

Cura和Slic3r等工具导出的是GCODE格式。GCODE格式使用明文描述路径。Sailfish Firmware只支持X3G文件,是一种二进制文件。由于打印机所使用的CPU速度较慢,处理文件并转换成脉冲比较慢,会影响打印质量。所以使用GPX工具将GCODE转换为X3G后,每个指令所走的位置都已经转换成脉冲,甚至可以对一些路径进行加减速的处理。打印机的CPU就可以直接的读取脉冲并控制电机运动。

XY steps/mm矫正

在转换的过程中,XY的steps per mm这个参数非常重要,讲的是走一个毫米需要多少的脉冲,如果该值过小,则会少走一些距离,造成距离偏小。这个和机器的结构有一定的关系,牵扯到同步齿的齿数、电机的参数等,RepRap Calculator提供了这个参数的计算器,非常方便。

calculator

MBot最初用的是17齿的齿轮,和Replicator是一样的。后来经过改进用了18齿的齿轮,和Replicator 2是一样的。通过计算器可以看到,88.89 steps/mm是理论值,但是MBot和Replicator 2中用的是88.573186这个值。和88.89比较起来,会少走一些距离,导致最后打印尺寸偏小。dcnewman开发的GPX提供了正确的参数,但截至目前尚有一些问题,不建议使用。

为了矫正88.57带来的误差,可以采用自定义的配置文件进行配置。mbot.ini是我的Mbot Cube的配置文件,在使用gpx的时候,指定gpx -c mbot.ini xxxx.gcode即可正确转换。

当然你的打印机可能依然不是正确的,需要使用一些工具进行矫正。传统的做法是使用20mm calibration box,测量外观尺寸。但这样做有一个缺点,由于喷头挤出的塑料可能有误差,会造成纠正的值将外壳的误差也算进去了。正确的测量方式是使用calibration sticks,根据不同的打印平台的长度,分别进行XY的测量,然后测量出两个缺口的距离。这样可以排除喷头的误差。

medium_9001test

我的打印机使用88.89,打印出来的距离正确。

AB轴喷头纠正

喷头的step per mm会对挤出的塑料的多少有影响,在机械结构不变的情况下,该值越大,则挤出的料越多。过多的料称之为过挤出,会造成外观尺寸偏大,内圆半径变小,顶层可见各种重叠的塑料;挤出过小,会造成外观尺寸变小,内圆半径变大,顶层可以见各种孔洞。正确的喷头参数,会对打印质量造成非常大的影响。

Calibrate your 3D printer提供了调整喷头的参数方法,当然这篇文章也提到了如何修正其它参数。还有一种普遍使用的方式是在材料上做好标记,然后走10cm,测量实际走的长度。当然对于不能用print run的打印机,我写了一个gcode文件,执行后会自动走10cm,然后测量实际的长度。我的打印机是正确的,所以对于喷头也不用做过多的处理。

孔偏小

打印中非常常见的问题是孔变小,通常孔会变小0.5mm左右,如果打印这个图形,很可能会发现无法插上。测量孔的直径,会发现孔小0.5mm,而柱子的直径是正常的。

test_plug_preview_featured

我在MBot Cube打印,结果是这样。然而在FlashForge Creator Pro上面,则两个可以插上。这个问题困扰了我很久,至今还没有解决。试过将同样的gcode文件分别转换成两种机型的x3g进行打印,还是一样,所以可以排除一些切片器的问题。在研究这个问题中,有一些文章可以参考。

虽然我没用过最终解决这个问题,但以下是有一些方法可以改善这种问题:

  • 改变挤出量
    在Cura和Slic3r中,都有改变挤出量的选项。甚至在Simplify3D中,PLA材料的默认挤出量就是90%。经过测试,90%的挤出量比较合适,打出来的测试块刚好可以卡上。但是外观尺寸会同样变小0.2mm,内圆仍然小0.2mm,但圆柱也同样会小0.2mm,这样两个尺寸就刚好能够插入。更小的挤出量则会带来一些问题,不推荐设置。
    改变挤出量虽然能够缓解一些圆孔的问题,但也会影响顶层的质量。为了弥补这样的缺陷,只能将顶层的厚度设置为1mm,或者5层。这样顶层基本上就密闭了。
  • 喷头形状
    打印negative_space_tolerance_test.stl,我的打印机只能拆下来2个,只能说打印质量比较差。通过很多次的对比,发现喷头的Flat tip area(见下图)的大小会影响到tolerance的,厂商已经在着手改进中了。

nozzle_02_-1280x720

  • XY Size Compensation
    Slic3r中提供了一个XY Compensation的选项,在Dimension Errors中有提到。和改变挤出量不一样,这个直接对切片后的图形进行补偿,不会产生顶层孔洞的问题。
    在目前的Cura中还没提供这样的功能,但在Cura的开发15.06版本中,已经准备提供类似功能。Simplify3D在最新的版本中已经提供。
  • 从设计上规避
    在设计的阶段就根据孔的大小预留一些空间,但这样对于别人已经设计好的模型就很难修正了。并且你的打印机的修正量不一定适合别人。

圆不是圆

你可能会发现打印园的起始的连接部位会有一些凸起,并且圆可能是椭圆。如果观察一下打印时候的速度及噪音,你会发现在打印圆的时候可能会嘎吱嘎吱的响。这是因为园会拆分成多条直线,导致每条直线会起起停停,在速度较高的时候可能会造成一些丢步或者抖动。解决方法是打印周长的时候,选择小一些的速度,例如40mm/s,这样打印质量就会很好了。观察Simplify3D的GCODE,发现它可能对不同的周长做了不同的处理,小的圆弧走的速度较慢,打印质量很好。

顶层的洞

如果挤出正常,顶层出现孔洞,则需要将Top/Bottom的层数设置得更好,一般1mm左右能够得到很好的效果。另外infill的百分比也比较影响,因为infill很低(10%以下)的时候,打印Top的时候就会变成Bridge,造成打印质量下降。

打印错层

Sailfish Firmware中有一个Accerlation的选项,该选项打开时固件会根据当前的GCODE生成相应地加速度,使得打印机在降速和提速的时候,能够平稳的以一定的加速度进行提速。关闭时,会始终以电机的最大能力作为最大加速度进行加减速,当电机无法接受预定的速度时,会造成丢步,久而久之积累下造成打印错层。

打印机噪音

我的打印机一直有嘎嘎嘎的噪音,晚上打印的时候声音巨大,关上门隔一个屋子都能听到。轴承都是加了油还是一样。经过排查,最终发现是中间的塑料块裂了。这个塑料块的非常重要,应该是和XY的垂直度有很大的关系。换了以后基本上就恢复了。

第一层不粘连

第一层不粘连的问题,其实很头痛。和以下因素有关:

  • 喷头和第一层的高度
    一般保持到一张纸的厚度即可。
  • 第一层的挤出量。
    一般选择200%的挤出量会好一些
  • 温度
    一般第一层温度保持在230度比较好
  • 材料
    材料的影响包括材料的好坏和颜色。有些材料表面粗糙,挤出后会不粘连,然后卷到喷头上,越卷越多,造成打印失败。解决方法包括打印一个raft,减小速度
Share