风信子 IV

我翻了一下,应该是2010年8月的这篇《蝴蝶》,那时的我,还是柔软的、诗意的,这个我原本打算写她一生的朋友,我希望我的想法永远沉没在心底,永远不要再提。于是我用这首诗给这个故事划上了句号。

那时的我,刚刚结束了一段纷绕不断的感情,刚去了一家体制内的小公司,在上司和老板的全力支持下尽情地尝试着自己的想法与工作方式。“上帝关闭一扇门,必然打开一扇窗”,是我那个时刻的真实写照。

8月夏天的晚上,我约她在她的新家外面散散步聊聊天。她有了一个儿子,但我看来这个孩子似乎惧怕社交,在这点上,我建议她多带小孩出去玩玩,但她总是不愿意,把儿子当作易碎品一样呵护着。

那天晚上,我们在她家外的露天广场上,我再一次听着她讲她的打算,比如说想学习,想当个会计,这一次,我却不耐烦了。

“当时我劝你不要休学,你却不听,学校让你留了一级,你又再次休学,现在什么都晚了吧。”

“你根本就不了解我当时的情况,你没经历过,你难以想象……”

“是你总是把很普通寻常的事想得太严重了吧?你没啥特别,你的事也没啥特别的。”

于是她又给我讲了一遍,当初失恋是如何如何地痛苦,她的病又是如何如何地影响了她的学习成绩,她记不住任何东西,没办法继续回到课堂上去完成学业。

但我满脑子里想的是如何找到一个更强有力的理由来让她永远中止这些话题。最后她很小声但很坚定地说出了一句话:

“你永远也无法了解我。”

这句话彻底让我怔住了。

我想起她把自己反锁在宿舍阳台上大哭,把全寝室都吓坏了,是我敲开了她的门;

我想起她在我上铺躺了七天七夜什么都不吃什么也不喝,是我帮她买饭打水送零食;

我想起这么多年来,几乎所有同学都忘了世界上还有她这么一个人,但我一直牵挂着她的存在;

但这一切,由于她彻底的否定,现在都似乎失去了意义。

曾经我的理想中的一部分,希望尽我的可能帮助弱小者改变命运的那部分,从此就彻底死掉了。在这个世界上,其实我什么都做不了,何必再浪费我的时间在毫无意义的事情上呢?

那时候的几个月前,我也曾在一个晚上,一个特别冷的春天的晚上,心痛得都走不动路了;所有的人都用他们认为有效的话安慰着我,我的挚友给我念了一首《林中路》,年长者说,相信时间,时间会带走一切的;我选择了相信。其实对于那段感情,最伤害我的不是失败,而是被下了一个结论:“你反反复复纠结的不是感情,而是,你接受不了失败。”我没有告诉她我也曾经难过过,但依然乐观。

这句话让我明白了,在世上,谁也不可能真的了解谁,人们只愿意去了解、去相信自己愿意了解、相信的那部分。

大概在一两年后,我一个年轻同事读了这几篇博客,说特别感动,我说谢谢,他说:“这写的就是你自己吧?”然后让我笑出眼泪并花了不少时间来解释证明这真的不是我。人们大概也很难相信,一个人能够这么真实地写出另一个截然不同的人的内心世界。

自那天晚上之后,我和她再也没见过面。再后来我换了工作,经常出差,她打电话问我,能不能借用我的车来当滴滴司机,我婉拒了。再后来我们再也没有联系过。

2015年8月的一天,在首都机场线上,我对着一个座位站了半小时之久,一直认真地玩着手机。到站时座位上的人站了起来,我足足愣在原地10秒之久,时间带走了爱,也让人忘记了伤害,只留下了那份努力寻找记忆中熟悉的感觉。当我回过神来的时候,赶紧转过身,拿着手机的手却控制不住地发抖,注意力一片模糊,地铁的门似乎过了一万年才打开。我头也不回地走了,就连是不是他,我都再也不需要答案。

高中时看《安娜卡列尼娜》,我翻来复去看了很多遍的小说,但总是在安娜死后就看不下去了;我不明白为什么小说不就在此结束,还有这么多絮絮叨叨的剖析论述,明明是一个悲剧,最后却是另一个人皆大欢喜的结局。

现在想起来,原来这部小说当初对我真正影响最深的,却是列文。记起小说中列文有害羞脸红的毛病,当时居然在一段时间内“传染”了成天嘻哈成性的我,费了不少时间才忘掉小说中身临其境的描写的影响。

也许就和托尔斯泰的小说一样,上半部,我人生的上半生,都在看别人的故事,躲在别人身后思考,没有人真正地了解藏身在暗处的我,而下半部,才是我的故事的开始。

神话的衰落与概念的兴起

柏拉图八十一岁去世。在去世的那天晚上,他让色雷斯的女孩为他吹奏长笛。女孩找不到法的节拍。柏拉图动了一下手指,向她指出尺度。
s27292703埃里克·沃格林总是喜欢在每部著作的最后时刻神来一笔,令人拍案叫绝。《秩序与历史》第三卷《柏拉图与亚里士多德》是阅读挑战度非常高的一部著作,由于此前我只读过柏拉图的《蒂迈欧篇》和《裴多篇》,在此书上部《柏拉图》要跟着沃格林的思路穿越所有柏拉图的著作已经非常吃力,而最后这句话,让我完全陷入了迷惑不解的状态。

直到我查阅了《法篇》柏拉图关于音乐的描述,终于明白了“法的节拍”指代的含义:类似于东方的礼乐,柏拉图把音乐与伦理联系起来,调节人不同的情感,如热情、节制、放纵、颓废,等等。

有别于中国古代同时期的百家争鸣,柏拉图的天才在于,他几乎一个人就贯穿和调和了中国几大流派的思想,除了思想本身之外,他在诸多其它表现形式上注入了思想的隐喻,包括戏剧与音乐,这充分展示了柏拉图驾驭智慧的能力。

很多年前我读《蒂迈欧篇》时曾尝试理解柏拉图的思想,参见《蒂迈欧篇的思维体系》。沃格林这本著作和我有一致的地方:柏拉图在试图使用不断循环的结构来陈述变化,但不一致的地方在于,我认为柏拉图的思维结构是螺旋上升式的,参见《克氏思维印象》。

如果说柏拉图困顿于他的时代,定义了时代的问题,那么沃格林则很好地从后世的角度抓住了一条主线,把柏拉图所有的故事串连成画卷;沃格林最大的贡献还在于照亮了当时藏在暗处的背景,给予了读者无穷的启发而不是答案。这本《柏拉图与亚里士多德》,彻底解答了很多我一直以来找不到答案的问题。

部落与神话

神话一直以来,被视为远古人类“凝望星空”释放了无穷想象力的文学与艺术创作。历史永远在被颠覆、否定和改写,新的时代永远宣称比旧的时代更好。曾经我也尝试将神话与历史建立起联系,部落遗迹可以通过考古史来发掘,但由于文字记录的缺乏,还原其真实面目已经非常困难。沃格林抓住的线索,是精神的继承与延续。在《以色列与启示》中,他论述了近东地区史前社会与《创世纪》的关联;神话即氏族部落的传说。我们通过神话的投射,可以重现部落的遗产:最聪明的人发明了天文农业和商业知识,他们被誉为神;与猛兽搏斗、拓荒开疆的人们被称为英雄;部落的殖民带来新的城市,他们继承共同的神话体系,比如希腊神话来及于埃及。

而在公元前420年左右,也等同于中国春秋同时期,正是世界历史上部落社会全面衰亡、城邦世界崛起的时代。与东方“礼崩乐坏”相呼应的是,是西方神话的解体,从来带来的精神世界的危机。

神话之死

神话解体带来的第一个冲击是对原本“永生”的神进行“死”的宣判:柏拉图在《高尔吉亚篇》中探讨了死与永生的话题。这给予我们的启示是,那个时代的人或许并不能真正理解“生”与“死”,他们对远古部落的首领(即神)依然存活于世,仍在冥冥之中发挥力量深信不疑。

在神话时代,生与死的区分没有这么明显;在那个时候,俗世存在很容易被误认为是灵魂之生。
《高尔吉亚篇》第一次把生与死定义了出来,也许从这个意义上来说,苏格拉底之死,正是他本人用死划出了神话与人间的分割线,即不灭的部分不是神,而是人的灵魂:
在灵魂的发现与解放上,苏格拉底的生与死是一个决定性的事件……苏格拉底的生是灵魂通过死侵入俗世存在而得以解放的伟大典范;对苏格拉底的模仿成为其追随者尤其是柏拉图的生的秩序。
这是人民与诗人的神话被灵魂神话所取代,伴随着神的死亡随之即来的问题是,那些未死却获得了“灵魂之生”的人的地位应该是什么?用沃格林的语言,这是历史的秩序,早期即是(神对于人的)启示过程,而在苏格拉底和柏拉图的时代,这是人间权威的转移,也是人间对正义的第一次思考,由于人间有了“恶”的存在却再也无法借助神行使正义,对死后灵魂的审判被迫被创造了出来。

权力与哲学

柏拉图出身于雅典显贵之家,他原本有着正当并且远大的政治前途。然而在雅典三十僭主时期,柏拉图的政治生涯并不顺利,而目睹了苏格拉底的悲剧之后,柏拉图选择了“转变生命”,将他在城邦公共管理事务的投入,转为一种“深思熟虑”的努力。《理想国》是柏拉图构筑的模范城邦,其范式局限于当时的数学知识与管理能力,如城邦的大小是当时数学计数的极限,人口规模也是公共资源承载的极限,管理者的任命也局限于认知范畴,但柏拉图在构筑《理想国》中的过程,是人的意识,而非世俗权力的伟大发展:意识第一次揭示了秩序是如何创立与瓦解,当它被书写下来时,就意味着后世将可以实现和发展它。

经验的深处不是完全的黑夜;一点光明在黑暗中闪耀。深处能够被感知为痛苦、危险和恶,只是因为还存在另一种感觉,尽管这种感觉被压制、被隐藏。启发性探究,即探求,不是从外面到最初的经验这样进行的(仿佛它是一个死的主题),而是寻求(zetesis)成分存在于经验之中,并成长为探求。……探究概念并不涉及外在的对象,而是灵魂在对其深处的解释中发展出的符号。……它本质上仍是赫拉克利特式的寻求(zetesis)的处境,他简单地说:“我探究(edizesamen)自身。”
我们来看看柏拉图在《理想国》中使用或者说,创造了哪些思维的方法。

范式与隐喻

柏拉图的启发性探究,是在自我经验中寻找范式,是在自我表达不同表现的隐喻,也是在自我尝试推论。沃格林点出了柏拉图未能直接了当点出的话:”城邦是大写的人。”而用我们今天的话说,柏拉图是在一组概念中发现了关联性:




















神话时代城邦时代
城邦
守护神统治者
生活范式政制

指代

在尝试寻找城邦“好的范式”时,柏拉图使用了“戏剧化”手法,比如,他尝试建立起一个戏剧,让苏格拉底在其中扮演统治者。再通过对虚拟的“立法”操作推论民众的反应,得出结论“应该在民众心中建立起政治秩序。”

引申

柏拉图借鉴了医学上的两个名词并扩展了其含义:形式(eidos)与本性(physis);这两个词原本分别指疾病症状和健康状态。柏拉图通过将城邦隐喻到人,暗示城邦“不好的政制”就如同人患病一样,是“原本”之上呈现的一种“形式”。形式、回归和朝向美,可以使得城邦恢复正常秩序。

沃格林对《理想国》进行了概括性的总结,从精神发展角度,我认为前四点就足够:

  1. 首先是《理想国》的对话作为全面的象征形式;
  2. 在对话内开展了探求(zetema),即从深处的黑暗走向高处和光明的探究;
  3. 在探求内上演了建立好城邦的戏剧,苏格拉底扮演城邦建立者(oikistes)的角色;
  4. 在建立戏剧内开展了对好城邦本性的认知探究。
    柏拉图在戏剧中采用的象征手法,在当时被证明了:一旦象征被提出来并被识别出来了,它就很容易被理解。柏拉图的另一个贡献是分类手法,他根据范式的不同,将城邦分为:
  1. 原始的城邦
  2. 奢侈的城邦
  3. 净化的城邦
  4. 哲学家的城邦
    而与柏拉图试图建立起理想国的区别,也就是苏格拉底的智慧之处则在于,他迅速识别出了时代的新生力量:年轻人需要能够找到自己位置的城邦。它是奢侈的城邦。

自然到人类历史

如今我们已经懂得,城邦的必然崛起与权威的转移是因为财富的积累。而在柏拉图与苏格拉底的时代,他们缺乏足够的认知来突破这个局限,所以在经过《斐多篇》和《政治家篇》继续的理论探究之后,柏拉图在《蒂迈欧篇》和《克里底亚篇》把视线投回了远古神话时代。《蒂迈欧篇》向我们展示了一个史前文明的辉煌世纪,试图告诫雅典人,当下的时代并非更好,远在上万年前,雅典的祖先就已经非常幸福了;而《克里底亚篇》,即记载了亚特兰蒂斯传说的著作,则启示了“恶”的后果。柏拉图依然把恶的终结寄托于神:

他在最后结束语中写道,诸神之神意识到即将发生的灾难,想通过惩罚来恢复适度的状态:“为了这个目的,他在最高贵的住所将所有神聚在一起,这个住处位于宇宙的中心,从高处俯瞰所有参与流变的事物,把他们聚在一起后,他说……”在这个时候,《克里底亚篇》戛然而止。
亚特兰蒂斯的灭亡,除了指代人间“恶”的惩罚之外,柏拉图的伟大发现在于揭示了一个事实:人类用自己的腐化与不完美,与自然的和谐(神的美德)相决裂,走入了自己谱写的历史。这个事实的伟大的启示是人与自然属性的分离:作为“神的秩序”的亚特兰蒂斯的灭亡,与作为“人的秩序”的雅典的胜利。

在神的“秩序”与人的“失序”之间,由“命运”接管。此后的雅典,也并非迎来了永久的和平与幸福,但翻开人类的历史,哪一次毁灭与重建,不是人类自身的选择?

精神

《法篇》是柏拉图最后一篇著作,这时他已经到了老年,他尝试建立起人间的秩序。他依然使用了诸多手法,使用“严肃的戏剧”,建立起政治结构。但Jan Huizinga清楚地阐明了柏拉图一生最伟大的贡献:

我们在戏剧中认识到精神。戏剧不是物质——无论其本质是什么。即使在动物世界中,它也突破了纯粹的物质生存。如果我们从由力量及其影响决定世界的视角看待它,这是一种多余,在这个词的全部意义上,即多余的东西。只有通过废除绝对决定的精神的涌入,戏剧现象才成为可能、可想、可理解。戏剧的存在一次又一次地确认了我们在宇宙中状况的超逻辑性。
写完《法篇》之后,柏拉图的一生结束了。但他所开创的所有精神遗产,由另一位伟大的学生推进到更伟大的颠峰。
柏拉图八十一岁去世。在去世的那天晚上,他让色雷斯的女孩为他吹奏长笛。女孩找不到法的节拍。柏拉图动了一下手指,向她指出尺度。

时代精神

柏拉图指出了法的节拍,也指出了他那个时代的精神;他目睹了雅典的衰退,也给雅典判了死刑;他看出了历史的循环,而他的学生亚里士多德则见证了整个希腊世界的瓦解;柏拉图的时代政治、教育和宗教紧密地整合,而在亚里士多德的时代,政治、宗教与智力生活明显出现了分化,这是人们常常谈到的文明的危机或解体:政治指向了旧的生活,而其它部分(可能是宗教)则展示出了未来的生活。

柏拉图的作品中,我们看出他的忧郁和紧张,这种紧张来自于他想要实现不可能的事:试图恢复精神与权力统一的神权政治;而在亚里士多德那里,我们感受到一种冷静和沉着,这种冷静和沉着来自于他已经“放弃”了那种政治。对于这个人而言,危机的重点不再是雅典的苦难,而在于如何开始于柏拉图开创的新生活。一个时代诞生了,它开创了理智新的高度。
人类物种有着结构明确的循环,但亚里士多德不再在特定文明的政治发展和衰退中寻找这种结构的法则了。人类精神史上而不是政治领域的事件标识出了这个时代——尽管政治可能在衰退……

科学与沉思

亚里士多德走出了政治领域,他提出了科学或哲学见解的发现与再发现,比如天象与乙醚作用,他指出在神话传说中也有相同记载:

科学发现在人身上不只出现一次、两次或少数几次,而是无限次地反复出现。
亚里士多德的所有著作,均对柏拉图“时代精神”进行了概括与发展,包括政治学、科学与伦理学。作为马其顿国王的老师,他比柏拉图纯粹精神的探究具备更多实践的可能性,并从中发展起实践批判,针对柏拉图的《理想国》,亚里士多德在《政治学》中写道:
我们不应该忽视人类的经验,如果这样的方案有任何好处,它们不可能长时间都未被发现。因为,几乎所有事物都已经被发现;尽管不是所有已经被发现的事物都已经被适合地收集和盘点,也不是所有被了解的事物都已经被付诸实践。
亚里士多德的思维核心依然建立在循环理论之上,人类似乎所有的命题,都曾经得到过神的启发,而在统治大众的必要性压力下衰退。当哲学家把自己从政治负累中解脱出来时,它可能得到恢复,衰退的原因可以在文明的政治部分中去寻找。他在《形而上学》中说:“爱神话的人在一定意义上是爱智慧的人。”
爱智慧、孤独与神话的奇迹——那是真理在其中被发现、丧失和恢复的时间无限性的崇高表示。

概念

苏格拉底的诘问,用现世人的观念来表述,是利用了古人在“概念”上的含混不清。而从启示、神话、生死到科学,每一步都凝聚了无限的精神探索力量才得以发现。后亚里士多德的时代,苏格拉底—柏拉图的精神火光已经开始衰竭。从世界史和欧洲史上的定义,罗马—中世纪带来的黑暗时代,思想早已停滞不前,没有人敢于撼动亚里士多德的权威,一切都已经被充分定义。

但沃格林在这本书与巧妙地扣了柏拉图的循环。与亚里士多德同时代的一个年轻人,皮浪(公元前363—前275)的主张是:

为了获得幸福我们必须首先考虑幸福是什么,其次我们考虑我们对它采取何种态度,再考虑作为结果产生的心理状态是什么。
这段话给我极大的震憾。首先它第一次揭示了“概念”与“感觉”的分离,这是直到黑格尔在《精神现象学》中才有清晰的论证;其次在思想史上,我们通常认为人的自我意识的觉醒在于18世纪的表现主义:当自我既明确他的意图又实现了他的意图时,生命即得到了圆满。托马斯·泰勒在《黑格尔》一书中说:“这是为18世纪末革命奠定基础的关键理念之一。但是它还远远不止如此;它是从那以后成长起来的文明的根本理念之一。在不同形式里,它是改变了当今世界的重要观念力量之一。”

2015年老照片儿

照相机的发明就是为了少写点字,2015年结束了,因为随身配备了iPhone 6神器,回顾竟然是这样的好写。

IMG_0116

年初TWer们在客户现场一起攻克技术难点 @北京

IMG_0290

在成都办公参加的最后一次Friday Drink @成都

IMG_0412

“大师组”来到深圳 @深圳

IMG_0831

难免在一起吃喝玩乐 @深圳

IMG_0420

大魔头的生日 @上海

FullSizeRender

盛夏游广州坐渡船 @广州

IMG_1112

Tid大会演讲 @北京

FullSizeRender 2

国际冠军杯米兰德比 @深圳

FullSizeRender 3

秋游颐和园 @北京

IMG_1437

光之穹顶一 @高雄

IMG_1442

光之穹顶二 @高雄

IMG_1565

西子湾 @高雄

IMG_1584

爱河入海 @高雄美术馆

IMG_1591

气爆纪念影展 @高雄美术馆

IMG_1985

宝安机场 @深圳

平民对王的胜利

希罗多德和荷马的区别在于,荷马无法抗争神给予人的命运,只得把他们吟唱入史诗;而希罗多德洞悉了人的弱点,而将他们叙述进了历史。所以特洛伊成为了一场神性的战争,而希波战争则是一场人性的战争。

这部著作经常被译为《希波战争史》,虽然确实完整地记载了两次希波战争,但内容其实是非常跳跃的,可以算作是记载了整个古地中海文明,大约公元前1000年到第二次希波战争结束的所有传说和事件。

希腊人的文明起源于埃及,这是希罗多德当时论述的,而且举出了很多的证据:包括希腊的神全部来自于埃及,希腊的很多习俗是从埃及人学来的,一些希腊居民祖先是埃及的移民,等等。这在近现代的古希腊研究书籍中却很少被人提及,更多是把希腊伊奥里亚文明当作独立一派来研究,也许是跟后来埃及文明的没落有关系。

说到埃及,在希罗多德历史前半部分有很多篇幅讲到。希罗多德说,埃及人很注重把发生的事情记录下来,并且写道:

凡是从事农业的民族都有记录过去所发生的事情的习惯。
不由得惊叹他的观察力。在当时的地中海沿岸,从事农耕的埃及人,航海的腓尼基人、雅典人,游牧的斯奇提亚人,大杂烩的波斯人,丰富的经济形态和频繁的民族间交流,都拓宽了希罗多德的视野,使得他得到了一种中立的智慧心态,以旁观者的角度为后世叙述这一切。而对波斯人的叙述,又不得不让我惊奇了:
波斯人并不是一个纯粹的民族,也没有特别信仰的神,他们祭祀的方法是登上最高的山,在上面向天奉献牺牲。

只要是别的民族好的,他们都吸收进来,只要认同波斯,他们就接纳为自己人。
是不是和古代中国有特别相似的感觉?当然下面还有一件更神奇的事儿了。希罗多德说,在当时的世界,没有任何人比波斯人更擅长快速传递信息:
他们在马走一天的路程终点设置驿站,在那里安排另一个人和另一匹马,然后每一段这样的路程都有这样一个驿站。就像希腊人在奥林匹克上的接力比赛一样,第一个人骑马传来信息,第二个人带着这个信息传递给下一个人,这样信息就迅速地传递到目的地了。
据书中所记载,波斯向东方最远攻占的地方为印度,印度人也作为希波战争的一员参加了到希腊本土的战争,向最北方攻克的大约是今哈萨克斯坦的地方,波斯和中国的距离越过西域是很近的,印度和中国的交往也很频繁,但希罗多德在内的大多数希腊人却完全不知道中国的存在,这个原因我一会分析。

另一个让人感兴趣的就是半农半牧的斯奇提亚人。他们本来是游牧民族,没有城镇,坐着马车到处迁移,并且骁勇善战,正因为这个特点,让他们采用游击战术在广袤的大地上跑来跑去,把波斯大帝居鲁士绕得疲于奔命,最后还葬身在斯奇提亚人手中。斯奇提亚人另一个特点是喜欢把杀死的敌人的头盖骨锯下来,镶上黄金制作成金碗,到了盛大的日子就把这个碗拿出来喝酒或是款待客人。这个习俗也出现在西藏,但不是敌人而是奴隶了。

现在我说一下为什么希腊人不知道有中国的存在。从书中的记载,伯罗奔尼撒人是不擅长航海的,而雅典人最远也只敢于航行到赫拉克勒斯柱(今直布罗陀海峡);据说腓尼基人曾经由于埃及法老的赞助绕着非洲航行过一圈,但他们都止步于东方。希罗多德的见闻其实是止步于波斯了,如果说希腊人同埃及人的往来非常密切的话,希腊对波斯的态度实际上是恐惧。所有的交流都几乎是波斯向希腊本土派出使者要求臣服,而希腊本土过去的要么是被驱逐,要么是用间。这些都阻止了希腊从波斯得到真正有价值的文化。

而波斯,在这部历史书中,表现出了最令人惊叹的一面,就是他们的王族。也许由于希腊人对波斯人的细节了解甚少,而把许多事情的源头写到了波斯王身上,但许多事情,仍表现出了作为王族的伟大之处。

首先,波斯帝国起源于居鲁士。在他之前,他的民族是美地亚的臣民,并且地位低贱;巧的是居鲁士其实是美地亚国王的外孙,因为国王做了一个梦,他的女儿生的孩子会把他的民族颠覆,于是他把女儿嫁给了波斯人并设法杀掉生下的孩子,以为这样他就断然没办法继承王位了。没想到这个孩子活了下来,最后长大了并且带领波斯人推翻了他的统治;然后击败了当时另一个强大的吕底亚帝国。

居鲁士保留了美地亚、吕底亚国王的特点,或者说是王族的特点,对身份尊贵的人加以厚待,对智慧保持着敬畏之心。吕底亚的国王曾经和梭伦对话,在临死之前说出当时梭伦给他的劝戒而被居鲁士赦免,并一直留在宫中作为谋士。

大流士则是另一个传奇,在于他对君主制的思考。希腊人普遍认为波斯帝国是专制的,但恰恰是波斯帝国赶跑了许多希腊城城邦的僭主统治,把民主交还给平民;另外在发动政变推翻了冒牌的居鲁士儿子后,波斯人关于他们从此应该实行民主制还是君主制举行了大辩论和投票,这不能不让现代人佩服。在这一场辩论中,大流士以:

即使实行民主制,人们也无法停止对高下的竞争,最后还是会让一人成为最终的胜利者,既然如此,为什么不选择君主制呢?
的论点获得了制度的胜利,这个胜利的意义在于,波斯人选择君主制,不是因为被某一个人攻克和征服,乃是大多数波斯人认为君主制是最好的制度。

而希腊人则是部落发展而来的平民社会。他们几乎一直处于贫穷和战事之中,他们大多数土地都非常贫瘠,即使是部落国王,也得亲自种地,王后还得亲自做饭;斯巴达的国王也没有特别多的财产。每当战事来临,国王和贵族、知名人士就得出征,以战死沙场为荣,有的城邦甚至出现奴隶反客为主霸占了城市,雅典这个城市也数次因为战争而几次重振自己的部落划分。所以希腊的平民式民主带有原始部落社会的遗产,这是一种由于财富还没有高度积累起来的生态,而只有在外界压力迫近时,原本没有多少远见的平民才开始抱团合力了。

雅典人的祖辈是伊奥尼亚人,而斯巴达人据说是多里斯人。这两个民族本来是希腊人中最低贱的,伯罗奔尼撒半岛早期的王族即荷马时代的阿伽门农,传说时期的赫拉克勒斯,可以说,最早居住在伯罗奔尼撒的人开创了希腊的英雄时代,荷马之前,希腊早已衰落,史称黑暗时代,希腊人只能用神话来追忆过去祖先的功绩,这个神话的终结点就是赫拉克勒斯的死亡和他后代的诅咒,伯罗奔尼撒沦陷在多里斯人的手中。当然这些传说都是很零散和混乱的,但从神话以来,伯罗奔尼撒人就是希腊人的首领和统帅,而不是雅典人。

两次希波战争也表现出了后来雅典和斯巴达争霸的必然性。第一次马拉松战役雅典人孤军击败波斯大军,斯巴达人正在家里举行祭典;第二次是斯巴达人以温泉关战役赢得了名誉,杀死波斯陆军两万人,但他们三百人全军覆没了,雅典人却在撒拉米斯海战全歼波斯海军。两场战役的共同特点是希腊人占据了地利,在人数远远少于敌军的情况下,斯巴达人选择在狭窄的地峡作战,雅典人选择在狭窄的海峡作战,这让他们在同一时刻仅面对着少量的敌军,从而凭借更优秀的战斗素质歼灭了对方。

但斯巴达人比起雅典人却少了谋略。在温泉关大军军心动摇之际,斯巴达国王奇奥尼达斯让其它民族的军队都回家了,选择了孤军决一死战;而雅典人在撒拉米斯各个民族争吵不休时,悄悄派出使者告诉波斯王薛西斯:

希腊人已经乱成一团了并商量着逃跑了,在他们逃跑之前,赶快将他们围住并切断后路。
第二天当希腊人发现自己已经被围困,他们停止了争吵并尽全力一战。这就是雅典人的谋略,在此之前,他们已经不止一次使用其它诡计,比如贿赂,来拉拢各派与他们共同作战,甚至更早时,他们通过贿赂德尔斐祭司佩提亚用神谕让斯巴达人把他们从僭主统治下解放出来。

巧的是,绕去伯罗奔尼撒断后的另一支波斯海军,被暴风雨完全摧毁了,而后薛西斯逃回波斯,留下挑起事端的玛尔多纽斯率五万大军继续与希腊人对峙;历史再一次重演,雅典的平民用与波斯缔结和约的计谋迫使斯巴达人出战,并在陆上取代另一支显赫的伯罗奔尼撒民族铁该亚人,与斯巴达人分居两翼,击溃了美地亚大军,波斯军队中与雅典人拥有共同先辈的伊奥尼亚人选择在阵地上倒戈;然后在整个环地中海曾经臣服于波斯的伊奥尼亚人的群起反抗洪流中,波斯帝国的辉煌过去了,一场平民对贵族的争霸也开始了……

传统业务如何互联网+

本周,我想兑换一张国航机票。
通过国航APP搜索,订票时它说我名字不是中文,这个错误是之前国航会员和凤凰知音会员帐户合并时产生的,它错误地把我的护照拼音名字合并到了会员帐户,并且还不允许我修改。此前在柜台办理值机时工作人员就给我说有问题,后来我添加了一个乘机人,每次买票都要重新选一次,总算让登机牌打印上了中文名字。

这次影响到了我的兑票,就必须联系凤凰知音修改了。经过5~6次提示语“现在路线正忙,请您耐心等待”之后,接线员给我说必须通过邮件形式发送修改信息和身份证照片到凤凰知音VIP邮箱,三个工作日内可以修改。根据接收的短信,我发了一封邮件。

等到第三天,我的名字还是拼音。经过再次尝试APP兑换,我发现界面虽然不能改名字,但可以改证件,选择通过护照购买,输入护照号码,然后收到“系统繁忙,请您稍后再试”的提示语。每一次“再试”我都得重新输入一次密码,每次重新兑换我都得重新选择城市、选择日期、搜索机票、修改为护照、输入护照号码、输入密码,为了一张¥1500元的机票,我也是蛮拼的。最后还是“系统繁忙”。

今天,我决定通过国航网站再试一试。哇,这次顺利地进入了兑换界面,并且网页上是可以自行输入姓名身份证号码!激动地进入最后的支付界面,它告诉我找不到兑换承让人……

最后一招是拨打客服电话。先试图进入贵宾会员菜单,不幸不被识别为贵宾。转里程兑换菜单,耐心等待了一次提示音,不到十分钟声音甜美的客服MM就帮助我办理完了机票兑换,密码输入、税费支付全部通过电话按键完成。办完后我问了一句:“为什么通过APP和网站办理不了兑换呢?”客服MM耐心地回答说:“那是因为系统太过繁忙。”又追问了一下我的信息修改进度,客户MM首先表示没有看到有邮件往来记录,然后询问了我的邮箱地址,表示未收到邮件,让我再发一次。只得作罢,挂了电话才记得是用另一个邮箱发的……

与此相似的经历,是办理移动业务,我也偏爱拨打10086——因为“移动营业厅”界面的复杂程度直接把我吓退了。好在没浪费我什么时间。

这些业务的共同特点是,流程较为固定,用户的目的性很强,而不像一般的互联网消费品那样,需要大量浏览、对比和决定。我们喜欢在电商网站中面对着各种图片、评论长时间地浏览,但经常在传统业务的办事大厅头就开始眩晕。

于是我开始分析:对比网站甚至APP,简单地拨打数字 + 对话操作的方式无疑是最优的;即使反复等待接线员,最后处理的效率还是高于当下的互联网端。这是因为,输入数字比查找信息快捷,传统企业又很擅长和客户通过短信互动,就算没有记录,号码也可以轻易地从近期短信中找到;客服具备专业性,同样的操作,远远比用户高效,后台系统“繁忙”程度也远远低于外网……

我们需要一个什么样的传统业务互联网产品?

有比输入电话号码更好的方式吗?

简单设计:比如用“里程换票”、“购票”这样气泡代替一个接一个子菜单,携程和去哪儿网的界面在这方面做得不错,虽然美观上还有待提升。做得最好的之一,我认为是Apple Music的初始界面。

2015-06-30-20.51.41

能不能更多采用语音交流?

既然客服交流体验这样好,为什么不采用语音技术来做呢?在这个领域,还是Apple的Siri领先了。

记住用户的选择?

看看我之前噩梦一样的反复输入吧,为什么APP就不能聪明一点,有一点记忆能力呢?谁也不愿意被“白痴”服务吧。

成为服务专家?

对于传统企业,买完产品看服务,我们需要的是专业的服务人员,而不是仅仅给用户开一个自助服务的新渠道完事。

那么,做这些事需要什么样的技术?

一流的体验设计师

记住,这是企业全新的产品线,请按照产品建设来进行投资,而不是随便搞一个网页。

语音技术

语音识别有一些技术壁垒,对企业来说,当前可以考虑一些商业产品,重心放在业务设计上。

数据分析

通过数据来认知用户的特点,进行细分,从而优化自己的产品。

云平台化

无论是解决“系统繁忙”的问题,还是支撑更多样的用户体验,更快速的数据分析,都离不开平台的支撑,否则,一切都只有从零开始。云计算将硬件资源虚拟化变为可按需使用,而云平台解决了不少系统架构的难点:扩容、高可用以及运行状态监控,通过云服务商的产品线完善,更是将软件的复用程度从包、组件提升到了应用程序级别。

基于云平台进行产品开发,将会大大提速传统企业进入互联网+时代,先行者甚至可以构建出自己的行业云,一举反超过去的巨头,这也是当今传统IT领域最至关重要的转型点。

佩提亚的低语

我能数沙,我能测海

我懂得沉默并了解聋人的意思

硬壳龟的香味触动了我的心

它和羊羔的肉一同在青铜锅里煮着

下面铺着青铜,上面盖着青铜
德尔斐神殿的先知佩提亚用上面一首六步格的诗,猜出了吕底亚国王的谜题,从而奠定了德尔斐在先知占卜的最高地位,也拉开了第一次小亚细亚战争的序幕。
阿尔卡地亚的平坦的原野上有铁该亚这样一个地方

在那里绝对无可避免地有两股风在吹着

一个打击打过来另一个打击必定打过去

祸与祸重叠无已

万物之母的大地就在那里包藏着阿伽门农的儿子

把他带到你们的城里来

那样你就成了铁该亚的主人
在征服铁该亚之前,斯巴达屡战屡败,神启示他们只有找到阿伽门农的儿子的遗体,才能征服铁该亚。斯巴达人遍寻不得之时,向佩提亚问卜,得到了上面的预言。

这首诗现在看来,有惊人的寓意。因为斯巴达最终破解它的含义,是在铁该亚一家铁匠铺里,风箱和打铁,以及铁刃带来的伤害,让斯巴达人确信阿伽门农儿子的尸体埋在这地下。故事告诉我们斯巴达人租了这家铁匠铺并秘密挖掘了尸体,最后打败了铁该亚人;但历史的猜测,何尝不是斯巴达人掌握了铁该亚人对铁的锻冶技术?

佩提亚,贯穿着整部《希罗多德历史》,决定着家族的盛衰,左右了城邦的兴替。

先知并不神秘。某种观念认为,希腊城邦时代的先知预判智慧来源于对信息的汇聚,大量问卜的人使得他们成为交流的中心点。但作为那个时代的特定角色,历史就在他们神秘的低语中,演进着,平衡着……

变革之心

第一则

天下治平,无故而发大难之端;吾发之,吾能收之,然后有辞于天下。事至而循循焉欲去之,使他人任其责,则天下之祸,必集于我。

第二则

匹夫见辱,拔剑而起,挺身而斗,此不足为勇也。天下有大勇者,卒然临之而不惊,无故加之而不怒,此其所挟持者甚大,而其志甚远也。

第三则

夫君子之所有取者远,则必有所待;所就者大,则必有所忍。贾生志大而量小,才有余而识不足也。

第四则

疾风知劲草,板荡识诚臣;勇夫安知义,智者必怀仁。

Netflix API优化之路

美国在线视频商Netflix近些年引领着技术潮流,尤其是他们的一系列开源框架Netflix OSS,被整合入Spring Cloud成为新一代开源解决方案Pivotal的分布式系统开发框架。Netflix也是最早成功采用Microservice架构的公司之一,他们的架构演进来自于API平台部门(Netflix API Platform)的不断优化;这篇文章根据Netflix的技术博客,来讲一讲这段演进过程。

与许多互联网应用一样,Netflix采用了面向接口或服务的架构分离了界面层与数据层,API逐渐发展为了整个Netflix最核心的系统。2010年以后,Netflix的在线用户不断攀升,在2011年初已达到了200亿日请求量;通过架构评估,很明显,2008年的设计已经不再合适,Netflix需要一套新的API来适应他们的未来。

netflix-api-request-growth

全新的业务目标

Netflix梳理了他们的业务方向,发现,与这些年API开发需求的变化一致的是,Netflix的业务也改变了。过去,Netflix主要为用户提供DVD租赁,现在,虽然DVD业务还保留着,但流媒体业务在迅速增长;另外,Netflix不再只是向美国用户提供服务,而是打开了加拿大甚至面向着整个国际市场。这些业务的转变都意味着API功能的随之应变。

更高的性能要求

首先是降低已高达200亿的日请求数量。Netflix有大量的推荐算法,通过一系列的API调用最后渲染出最合适的用户界面。优化方式可以是,比如通过数据分析发现某类设备的请求占据了50%的请求比例,那么是否可能在API层封装一些“用户体验”,通过复用算法而减少API的调用计算步骤,从而大量减少请求数量?另外,如果把一切资源尽可能变成静态,是否可以降低25%左右的请求数量?Netflix事先做了大量的假设。

优化之前的架构

request-multi_1252

 

优化之后的架构

request-single_1252

其次是降低API的负载压力。Netflix的一项重要功能是对用户的使用体验进行了数据收集,在流媒体模式下,用户数量和停留时间上去后,这类请求也变得非常庞大。对此Netflix设计了支持Partial响应的API,从而降低了服务的负载。

分布式API开发

通常我们理解的分布式(Distribute)开发是指异地开发模式,而Netflix的Distribute意味着分权。通常一个企业会选择一类技术架构作为企业级技术架构选型,一种产品或一个系统在架构设计时也会确定其技术栈,目的都是通过一致性技术积累降低学习成本和开发难度。而Netflix彻彻底底改变了这个观点。

早期的Netflix是单一技术架构

netflix-api-pre-redesign-v2

到2013年,Netflix的流媒体已经支持了超过800种设备类型。用户和客户端的多样化,以及大数据等新技术的兴起,导致了Netflix必须招纳各类语言的人才,包括Javascript、Objective-C、Java、C、C#、Ruby、Python等等,拥有这些不同编程背景,但在其领域都能称之为专家的人才,Netflix必须考虑在API开发上做到分权决策,并在技术层面添加一层Functional Reactive Programming Model支持多语言开发调用。

微服务架构

上面提到,Netflix已经支持超过800种设备。多样的用户特征和需求以及频繁的改动让他们认识到,一套解决方案(One Size Fits All API)甚至一个公共平台式的团队(如API Team、UI Team)已不再适用于Netflix的业务,因为:

  1. API的通用性变得越来越差;
  2. 针对每一类设备,即每一类用户群体的创新速度都被拖慢了,因为他们所需要的任何客户端功能都涉及到跨团队沟通;
  3. 所有的创新速度都被拖慢了,因为API团队成为了效率瓶颈,他们疲于对各种待实现的功能特性进行优先级排序,并不断地延期;
  4. 导致越来越复杂和超负荷的请求,响应效率越来越低下;
  5. 系统里堆满了各种难以理解的特性标记来区分路由不同客户端的功能以及数据。
    这一切,已经严重影响到了Netflix的用户需求实现、性能甚至创新。这就引出了现在被称为微服务(Microservcie)的架构方案,除了团队和架构上的分权自治,语言层面的兼容,因为服务的依赖复杂性,Netflix增加Hystrix回路熔断,这一套架构解决了以下问题:

  6. 某个API的停止服务不会破坏用户的使用体验;

  7. API在调用依赖失败时能够自动作出正确的选择判断;
  8. API能够报告它自己的状态,以及过去15~30分钟发生的事情。
    architecture-overview_1252

在2014年,再演进了一层Script以简化服务的调用,被称之为Dynamic Script Platform.

scriptplatform_apiserver2_25

 

它通过部署流水线来保证Script的正确性。

scriptpipelineforblogv1

API部署流程

Netflix采用的代码分支策略包含Test/Release/Prod三种固定分支。

  • 开发人员平时工作在Test分支上,它的提交可以触发测试环境的自动部署;
  • Release分支用于每周自动部署,只需要把代码提交到Release分支上,它会触发自动化测试及集成测试,后续过程会由某个特定成员或部署团队启动,所有的动作都是自动化的。部署完成之后,代码会自动Push到Prod分支上;
  • 如果某个特性需要立即发布而不是通过每周固定发布流程;开发人员可以向Prod分支提交,这次提交会自动触发Release分支的合并并触发自动部署流程,如果审核人员通过,它将被立即部署。
    Basic Build Test Deploy Flow

参考

http://www.infoq.com/news/2013/02/netflix-api-optimization/

http://techblog.netflix.com/2013/01/optimizing-netflix-api.html

http://techblog.netflix.com/2014/03/the-netflix-dynamic-scripting-platform.html

http://techblog.netflix.com/2013/08/deploying-netflix-api.html

锡箔时代(三)空与无的世界

那是2009年9月的深夜,我加班后搭上一辆出租车。

上车后司机说,本来要去另一个地方加气,因为我的路线刚好有一个偏僻的加气站,所以就载上我了。

“我开出租车,每条路线的时间我都会计算,找到最优化的方案。”

因为职业的缘故,我随口就问:“出租车司机都会有一套方案来提高收入?”

司机回答说:“不,大多数人都不会去想这些。”

长长的寂静之后,司机突然开口对我说道:“事物非常巧妙,如果你换一种角度,可以看到很多不同的东西。”

一般来说,我是一个不太喜欢和陌生人搭讪的人;但因为自己也喜欢哲学的缘故,或者在这种场合下遇到一个说出很有哲理性话语的人,让我觉得很有趣;于是我决定说三分话,探探对方的“底气”。

“想不到你还喜欢研究这些,”我说,“我平时也会看点儿哲学。”
那天我写了一篇文章,后来又丢失了,再后来我觉得那件事情挺有意思,有必要复盘一次,于是2010年10月31日,我试图重新写出当初那篇。写了个开头,突然觉得文字不够美妙了,终于到现在,也只保留了一个开头。

到现在,整整五年过去了,我几乎忘记了所有的细节,再写出来已经是不可能。但当时的感觉是新鲜的,在我的经历中,我从没想到过,一个出租车司机也有着深远的精神世界:佛教讲究空,空能容万物;道教讲究无,无为而无不为。

Hexagonal architecture

Create your application to work without either a UI or a database so you can run automated regression-tests against the application, work when the database becomes unavailable, and link applications together without any user involvement.

The Pattern: Ports and Adapters (“Object Structural”)

Alternative name: “Ports & Adapters”

Alternative name: “Hexagonal Architecture”

Intent

Allow an application to equally be driven by users, programs, automated test or batch scripts, and to be developed and tested in isolation from its eventual run-time devices and databases.

As events arrive from the outside world at a port, a technology-specific adapter converts it into a usable procedure call or message and passes it to the application. The application is blissfully ignorant of the nature of the input device. When the application has something to send out, it sends it out through a port to an adapter, which creates the appropriate signals needed by the receiving technology (human or automated). The application has a semantically sound interaction with the adapters on all sides of it, without actually knowing the nature of the things on the other side of the adapters.

Figure 1

Motivation

One of the great bugaboos of software applications over the years has been infiltration of business logic into the user interface code. The problem this causes is threefold:

  • First, the system can’t neatly be tested with automated test suites because part of the logic needing to be tested is dependent on oft-changing visual details such as field size and button placement;
  • For the exact same reason, it becomes impossible to shift from a human-driven use of the system to a batch-run system;
  • For still the same reason, it becomes difficult or impossible to allow the program to be driven by another program when that becomes attractive.
    The attempted solution, repeated in many organizations, is to create a new layer in the architecture, with the promise that this time, really and truly, no business logic will be put into the new layer. However, having no mechanism to detect when a violation of that promise occurs, the organization finds a few years later that the new layer is cluttered with business logic and the old problem has reappeared.

Imagine now that ‘’every’’ piece of functionality the application offers were available through an API (application programmed interface) or function call. In this situation, the test or QA department can run automated test scripts against the application to detect when any new coding breaks a previously working function. The business experts can create automated test cases, before the GUI details are finalized, that tells the programmers when they have done their work correctly (and these tests become the ones run by the test department). The application can be deployed in ‘’headless’’ mode, so only the API is available, and other programs can make use of its functionality — this simplifies the overall design of complex application suites and also permits business-to-business service applications to use each other without human intervention over the web. Finally, the automated function regression tests detect any violation of the promise to keep business logic out of the presentation layer. The organization can detect, and then correct, the logic leak.

An interesting similar problem exists on what is normally considered “the other side” of the application, where the application logic gets tied to an external database or other service. When the database server goes down or undergoes significant rework or replacement, the programmers can’t work because their work is tied to the presence of the database. This causes delay costs and often bad feelings between the people.

It is not obvious that the two problems are related, but there is a symmetry between them that shows up in the nature of the solution.

Nature of the Solution

Both the user-side and the server-side problems actually are caused by the same error in design and programming — the entanglement between the business logic and the interaction with external entities. The asymmetry to exploit is not that between ‘’left’’ and ‘’right’’ sides of the application but between ‘’inside’’ and ‘’outside’’ of the application. The rule to obey is that code pertaining to the ‘’inside’’ part should not leak into the ‘’outside’’ part.

Removing any left-right or up-down asymmetry for a moment, we see that the application communicates over ‘’ports’’ to external agencies. The word “port” is supposed to evoke thoughts of ‘’ports’’ in an operating system, where any device that adheres to the protocols of a port can be plugged into it; and ‘’ports’’ on electronics gadgets, where again, any device that fits the mechanical and electrical protocols can be plugged in.

  • The protocol for a port is given by the purpose of the conversation between the two devices.
    The protocol takes the form of an application program interface (API).

For each external device there is an ‘’adapter’’ that converts the API definition to the signals needed by that device and vice versa. A graphical user interface or GUI is an example of an adapter that maps the movements of a person to the API of the port. Other adapters that fit the same port are automated test harnesses such as FIT or Fitnesse, batch drivers, and any code needed for communication between applications across the enterprise or net.

On another side of the application, the application communicates with an external entity to get data. The protocol is typically a database protocol. From the application’s perspective, if the database is moved from a SQL database to a flat file or any other kind of database, the conversation across the API should not change. Additional adapters for the same port thus include an SQL adapter, a flat file adapter, and most importantly, an adapter to a “mock” database, one that sits in memory and doesn’t depend on the presence of the real database at all.

Many applications have only two ports: the user-side dialog and the database-side dialog. This gives them an asymmetric appearance, which makes it seem natural to build the application in a one-dimensional, three-, four-, or five-layer stacked architecture.

There are two problems with these drawings. First and worst, people tend not to take the “lines” in the layered drawing seriously. They let the application logic leak across the layer boundaries, causing the problems mentioned above. Secondly, there may be more than two ports to the application, so that the architecture does not fit into the one-dimensional layer drawing.

The hexagonal, or ports and adapters, architecture solves these problems by noting the symmetry in the situation: there is an application on the inside communicating over some number of ports with things on the outside. The items outside the application can be dealt with symmetrically.

The hexagon is intended to visually highlight

  1. the inside-outside asymmetry and the similar nature of ports, to get away from the one-dimensional layered picture and all that evokes, and
  2. the presence of a defined number of different ports – two, three, or four (four is most I have encountered to date).
    The hexagon is not a hexagon because the number six is important, but rather to allow the people doing the drawing to have room to insert ports and adapters as they need, not being constrained by a one-dimensional layered drawing. The term ‘’hexagonal architecture’’ comes from this visual effect.

The term “port and adapters” picks up the ‘’purposes’’ of the parts of the drawing. A port identifies a purposeful conversation. There will typically be multiple adapters for any one port, for various technologies that may plug into that port. Typically, these might include a phone answering machine, a human voice, a touch-tone phone, a graphical human interface, a test harness, a batch driver, an http interface, a direct program-to-program interface, a mock (in-memory) database, a real database (perhaps different databases for development, test, and real use).

In the Application Notes, the left-right asymmetry will be brought up again. However, the primary purpose of this pattern is to focus on the inside-outside asymmetry, pretending briefly that all external items are identical from the perspective of the application.

Structure

Figure 2

Figure 2 shows an application having two active ports and several adapters for each port. The two ports are the application-controlling side and the data-retrieval side. This drawing shows that the application can be equally driven by an automated, system-level regression test suite, by a human user, by a remote http application, or by another local application. On the data side, the application can be configured to run decoupled from external databases using an in-memory oracle, or ‘’mock’’, database replacement; or it can run against the test- or run-time database. The functional specification of the application, perhaps in use cases, is made against the inner hexagon’s interface and not against any one of the external technologies that might be used.

Figure 3

Figure 3 shows the same application mapped to a three-layer architectural drawing. To simplify the drawing only two adapters are shown for each port. This drawing is intended to show how multiple adapters fit in the top and bottom layers, and the sequence in which the various adapters are used during system development. The numbered arrows show the order in which a team might develop and use the application:

  1. With a FIT test harness driving the application and using the mock (in-memory) database substituting for the real database;
  2. Adding a GUI to the application, still running off the mock database;
  3. In integration testing, with automated test scripts (e.g., from Cruise Control) driving the application against a real database containing test data;
  4. In real use, with a person using the application to access a live database.

Sample Code

The simplest application that demonstrates the ports & adapters fortunately comes with the FIT documentation. It is a simple discount computing application:

discount(amount) = amount * rate(amount);

In our adaptation, the amount will come from the user and the rate will come from a database, so there will be two ports. We implement them in stages:

  • With tests but with a constant rate instead of a mock database,
  • then with the GUI,
  • then with a mock database that can be swapped out for a real database.
    Thanks to Gyan Sharma at IHC for providing the code for this example.

Stage 1: FIT App constant-as-mock-database

First we create the test cases as an HTML table (see the FIT documentation for this):

TestDiscounter
amount discount()
100 5
200 10

Note that the column names will become class and function names in our program. FIT contains ways to get rid of this “programmerese”, but for this article it is easier just to leave them in.

Knowing what the test data will be, we create the user-side adapter, the ColumnFixture that comes with FIT as shipped:

import fit.ColumnFixture;
public class TestDiscounter extends ColumnFixture {
private Discounter app = new Discounter();
public double amount;
public double discount() {
return app.discount(amount);
}
}

That’s actually all there is to the adapter. So far, the tests run from the command line (see the FIT book for the path you’ll need). We used this one:

set FIT_HOME=/FIT/FitLibraryForFit15Feb2005
java -cp %FIT_HOME%/lib/javaFit1.1b.jar;%FIT_HOME%/dist/fitLibraryForFit.jar;src;bin
fit.FileRunner test/Discounter.html TestDiscount_Output.html

FIT produces an output file with colors showing us what passed (or failed, in case we made a typo somewhere along the way).

At this point the code is ready to check in, hook into Cruise Control or your automated build machine, and include in the build-and-test suite.

Stage 2: UI App constant-as-mock-database

I’m going to let you create your own UI and have it drive the Discounter application, since the code is a bit long to include here. Some of the key lines in the code are these:

Discounter app = new Discounter();
public void actionPerformed(ActionEvent event) {
String amountStr = text1.getText();
double amount = Double.parseDouble(amountStr);
discount = app.discount(amount));
text3.setText( “” + discount );
}

At this point the application can be both demoed and regression tested. The user-side adapters are both running.

Stage 3: (FIT or UI) App mock database

To create a replaceable adapter for the database side, we create an ‘’interface’’ to a repository, a ‘’RepositoryFactory’’ that will produce either the mock database or the real service object, and the in-memory mock for the database.

public interface RateRepository {
double getRate(double amount);
}
public class RepositoryFactory {
public RepositoryFactory() {
super();
}
public static RateRepository getMockRateRepository() {
return new MockRateRepository();
}
}
public class MockRateRepository implements RateRepository {
public double getRate(double amount) {
if(amount <= 100) return 0.01;
if(amount <= 1000) return 0.02;
return 0.05;
}
}

To hook this adapter into the Discounter application, we need to update the application itself to accept a repository adapter to use, and the have the (FIT or UI) user-side adapter pass the repository to use (real or mock) into the constructor of the application itself. Here is the updated application and a FIT adapter that passes in a mock repository (the FIT adapter code to choose whether to pass in the mock or real repository’s adapter is longer without adding much new information, so I omit that version here).

import repository.RepositoryFactory;
import repository.RateRepository;
public class Discounter {
private RateRepository rateRepository;
public Discounter(RateRepository r) {
super();
rateRepository = r;
}
public double discount(double amount) {
double rate = rateRepository.getRate( amount );
return amount * rate;
}
}

import app.Discounter;
import fit.ColumnFixture;
public class TestDiscounter extends ColumnFixture {
private Discounter app =
new Discounter(RepositoryFactory.getMockRateRepository());
public double amount;
public double discount() {
return app.discount( amount );
}
}

That concludes implementation of the simplest version of the hexagonal architecture.

For a different implementation, using Ruby and Rack for browser usage, see https://github.com/totheralistair/SmallerWebHexagon

Application Notes

The Left-Right Asymmetry

The ports and adapters pattern is deliberately written pretending that all ports are fundamentally similar. That pretense is useful at the architectural level. In implementation, ports and adapters show up in two flavors, which I’ll call ‘’primary’’ and ‘’secondary’’, for soon-to-be-obvious reasons. They could be also called ‘’driving’’ adapters and ‘’driven’’ adapters.

The alert reader will have noticed that in all the examples given, FIT fixtures are used on the left-side ports and mocks on the right. In the three-layer architecture, FIT sits in the top layer and the mock sits in the bottom layer.

This is related to the idea from use cases of “primary actors” and “secondary actors”. A ‘’primary actor’’ is an actor that drives the application (takes it out of quiescent state to perform one of its advertised functions). A ‘’secondary actor’’ is one that the application drives, either to get answers from or to merely notify. The distinction between ‘’primary ‘’and’’ secondary ‘’lies in who triggers or is in charge of the conversation.

The natural test adapter to substitute for a ‘’primary’’ actor is FIT, since that framework is designed to read a script and drive the application. The natural test adapter to substitute for a ‘’secondary’’ actor such as a database is a mock, since that is designed to answer queries or record events from the application.

These observations lead us to follow the system’s use case context diagram and draw the ‘’primary ports ‘’and’’ primary adapters’’ on the left side (or top) of the hexagon, and the ‘’secondary ports’’ and ‘’secondary adapters’’ on the right (or bottom) side of the hexagon.

The relationship between primary and secondary ports/adapters and their respective implementation in FIT and mocks is useful to keep in mind, but it should be used as a consequence of using the ports and adapters architecture, not to short-circuit it. The ultimate benefit of a ports and adapters implementation is the ability to run the application in a fully isolated mode.

Use Cases And The Application Boundary

It is useful to use the hexagonal architecture pattern to reinforce the preferred way of writing use cases.

A common mistake is to write use cases to contain intimate knowledge of the technology sitting outside each port. These use cases have earned a justifiably bad name in the industry for being long, hard-to-read, boring, brittle, and expensive to maintain.

Understanding the ports and adapters architecture, we can see that the use cases should generally be written at the application boundary (the inner hexagon), to specify the functions and events supported by the application, regardless of external technology. These use cases are shorter, easier to read, less expensive to maintain, and more stable over time.

How Many Ports?

What exactly a port is and isn’t is largely a matter of taste. At the one extreme, every use case could be given its own port, producing hundreds of ports for many applications. Alternatively, one could imagine merging all primary ports and all secondary ports so there are only two ports, a left side and a right side.
Neither extreme appears optimal.

The weather system described in the Known Uses has four natural ports: the weather feed, the administrator, the notified subscribers, the subscriber database. A coffee machine controller has four natural ports: the user, the database containing the recipes and prices, the dispensers, and the coin box. A hospital medication system might have three: one for the nurse, one for the prescription database, and one for the computer-controller medication dispensers.
It doesn’t appear that there is any particular damage in choosing the “wrong” number of ports, so that remains a matter of intuition. My selection tends to favor a small number, two, three or four ports, as described above and in the Known Uses.

Known Uses

Figure 4

Figure 4 shows an application with four ports and several adapters at each port. This was derived from an application that listened for alerts from the national weather service about earthquakes, tornadoes, fires and floods, and notified people on their telephones or telephone answering machines. At the time we discussed this system, the system’s interfaces were identified and discussed by ‘’technology, linked to purpose’’. There was an interface for trigger-data arriving over a wire feed, one for notification data to be sent to answering machines, an administrative interface implemented in a GUI, and a database interface to get their subscriber data.

The people were struggling because they needed to add an http interface from the weather service, an email interface to their subscribers, and they had to find a way to bundle and unbundle their growing application suite for different customer purchasing preferences. They feared they were staring at a maintenance and testing nightmare as they had to implement, test and maintain separate versions for all combinations and permutations.

Their shift in design was to architect the system’s interfaces ‘’by purpose’’ rather than by technology, and to have the technologies be substitutable (on all sides) by adapters. They immediately picked up the ability to include the http feed and the email notification (the new adapters are shown in the drawing with dashed lines). By making each application executable in headless mode through APIs, they could add an app-to-add adapter and unbundle the application suite, connecting the sub-applications on demand. Finally, by making each application executable completely in isolation, with test and mock adapters in place, they gained the ability to regression test their applications with stand-alone automated test scripts.

Mac, Windows, Google, Flickr, Web 2.0

In the early 1990s, MacIntosh applications such as word processor applications were required to have API-drivable interfaces, so that applications and user-written scripts could access all the functions of the applications. Windows desktop applications have evolved the same ability (I don’t have the historical knowledge to say which came first, nor is that relevant to the point).

The current (2005) trend in web applications is to publish an API and let other web applications access those APIs directly. Thus, it is possible to publish local crime data over a Google map, or create web applications that include Flickr’s photo archiving and annotating abilities.

All of these examples are about making the ‘’primary ‘’ports’ APIs visible. We see no information here about the secondary ports.

Stored Outputs

This example written by Willem Bogaerts on the C2 wiki:

I encountered something similar, but mainly because my application layer had a strong tendency to become a telephone switchboard that managed things it should not do. My application generated output, showed it to the user and then had some possibility to store it as well. My main problem was that you did not need to store it always. So my application generated output, had to buffer it and present it to the user. Then, when the user decided that he wanted to store the output, the application retrieved the buffer and stored it for real.

I did not like this at all. Then I came up with a solution: Have a presentation control with storage facilities. Now the application no longer channels the output in different directions, but it simply outputs it to the presentation control. It’s the presentation control that buffers the answer and gives the user the possibility to store it.

The traditional layered architecture stresses “UI” and “storage” to be different. The Ports and Adapters Architecture can reduce output to being simply “output” again.

Anonymous example from the C2-wiki

In one project I worked on, we used the SystemMetaphor of a component stereo system. Each component has defined interfaces, each of which has a specific purpose. We can then connect components together in almost unlimited ways using simple cables and adapters.

Distributed, Large-Team Development

This one is still in trial use and so does not properly count as a use of the pattern. However, it is interesting to consider.
Teams in different locations all build to the Hexagonal architecture, using FIT and mocks so the applications or components can be tested in standalone mode. The CruiseControl build runs every half hour and runs all the applications using the FIT+mock combination. As application subsystem and databases get completed, the mocks are replaced with test databases.

Separating Development of UI and Application Logic

This one is still in early trial use and so does not count as a use of the pattern. However, it is interesting to consider.
The UI design is unstable, as they haven’t decided on a driving technology or a metaphor yet. The back-end services architecture hasn’t been decided, and in fact will probably change several times over the next six months. Nonetheless, the project has officially started and time is ticking by.

The application team creates FIT tests and mocks to isolate their application, and creates testable, demonstrable functionality to show their users. When the UI and back-end services decisions finally get met, it “should be straightforward” to add those elements the application. Stay tuned to learn how this works out (or try it yourself and write me to let me know).

Adapter

The ‘’Design Patterns’’ book contains a description of the generic ‘’Adapter’’ pattern: “Convert the interface of a class into another interace clients expect.” The ports-and-adapters pattern is a particular use of the ‘’Adapter’’ pattern.

Model-View-Controller

The MVC pattern was implemented as early as 1974 in the Smalltalk project. It has been given, over the years, many variations, such as Model-Interactor and Model-View-Presenter. Each of these implements the idea of ports-and-adapters on the primary ports, not the secondary ports.

Mock Objects and Loopback

“A mock object is a “double agent” used to test the behaviour of other objects. First, a mock object acts as a faux implementation of an interface or class that mimics the external behaviour of a true implementation. Second, a mock object observes how other objects interact with its methods and compares actual behaviour with preset expectations. When a discrepancy occurs, a mock object can interrupt the test and report the anomaly. If the discrepancy cannot be noted during the test, a verification method called by the tester ensures that all expectations have been met or failures reported.” — From http://MockObjects.com

Fully implemented according to the mock-object agenda, mock objects are used throughout an application, not just at the external interface The primary thrust of the mock object movement is conformance to specified protocol at the individual class and object level. I borrow their word “mock” as the best short description of an in-memory substitute for an external secondary actor.

The Loopback pattern is an explicit pattern for creating an internal replacement for an external device.

Pedestals

In “Patterns for Generating a Layered Architecture”, Barry Rubel describes a pattern about creating an axis of symmetry in control software that is very similar to ports and adapters. The ‘’Pedestal’’ pattern calls for implementing an object representing each hardware device within the system, and linking those objects together in a control layer. The ‘’Pedestal’’ pattern can be used to describe either side of the hexagonal architecture, but does not yet stress the similarity across adapters. Also, being written for a mechanical control environment, it is not so easy to see how to apply the pattern to IT applications.

Checks

Ward Cunningham’s pattern language for detecting and handling user input errors, is good for error handling across the inner hexagon boundaries.

Dependency Inversion (Dependency Injection) and SPRING

Bob Martin’s Dependency Inversion Principle (also called Dependency Injection by Martin Fowler) states that “High-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions.” The ‘’Dependency Injection ‘’pattern by Martin Fowler gives some implementations. These show how to create swappable secondary actor adapters. The code can be typed in directly, as done in the sample code in the article, or using configuration files and having the SPRING framework generate the equivalent code.

Acknowledgements

Thanks to Gyan Sharma at Intermountain Health Care for providing the sample code used here. Thanks to Rebecca Wirfs-Brock for her book ‘’Object Design’’, which when read together with the ‘’Adapter’’ pattern from the ‘’Design Patterns’’ book, helped me to understand what the hexagon was about. Thanks also to the people on Ward’s wiki, who provided comments about this pattern over the years (e.g., particularly Kevin Rutherford’s http://silkandspinach.net/blog/2004/07/hexagonal_soup.html).

FIT, A Framework for Integrating Testing: Cunningham, W., online at http://fit.c2.com, and Mugridge, R. and Cunningham, W., ‘’Fit for Developing Software’’, Prentice-Hall PTR, 2005.
The ‘’Adapter’’ pattern: in Gamma, E., Helm, R., Johnson, R., Vlissides, J., ‘’Design Patterns’’, Addison-Wesley, 1995, pp. 139-150.
The ‘’Pedestal’’ pattern: in Rubel, B., “Patterns for Generating a Layered Architecture”, in Coplien, J., Schmidt, D., ‘’PatternLanguages of Program Design’’, Addison-Wesley, 1995, pp. 119-150.
The ‘’Checks’’ pattern: by Cunningham, W., online at http://c2.com/ppr/checks.html
The ‘’Dependency Inversion Principle’‘: Martin, R., in ‘’Agile Software Development Principles Patterns and Practices’’, Prentice Hall, 2003, Chapter 11: “The Dependency-Inversion Principle”, and online at http://www.objectmentor.com/resources/articles/dip.pdf
The ‘’Dependency Injection’’ pattern: Fowler, M., online at http://www.martinfowler.com/articles/injection.html
The ‘’Mock Object’’ pattern: Freeman, S. online at http://MockObjects.com
The ‘’Loopback’’ pattern: Cockburn, A., online at http://c2.com/cgi/wiki?LoopBack
‘’Use cases:’’ Cockburn, A., ‘’Writing Effective Use Cases’’, Addison-Wesley, 2001, and Cockburn, A., “Structuring Use Cases with Goals”, online at http://alistair.cockburn.us/crystal/articles/sucwg/structuringucswithgoals.htm

http://alistair.cockburn.us/Hexagonal+architecture Alistair Cockburn

© 2018 Silent River All Rights Reserved. 本站访客数人次 本站总访问量
Theme by hiero