《万历十五年》书评

按照作者黄仁宇的说法,万历十五年,即1587年,是历史上极为平常的一年。这一年‘四海升平,全年并无大事可叙’,‘实为平平淡淡的一年’。既然平淡,作者何以要单单将这一年抽出来叙述呢?要理解作者的做法需要从作者的大历史观说起。

黄仁宇的历史研究从大的时空范围着手,强调不通过历史人物的生涯探讨和单一历史事件来分析历史,而是通过对历史社会面貌进行整体的分析和把握,掌握历史社会的结构特征。

万历十五年是五百年明清史中极为平常的一年,这也正是作者选取这一年作为研究切片的原因之一:从宏观上看,明清社会的根本问题从未改变,从这极为平常的一年着手,也可看出不变的矛盾并理解明清社会走向衰落的根本原因。

黄仁宇在这本书中对万历朝的诸多人物做了群像式的描绘。在他看来,传统中国社会以道德代替法律,阻碍了技术的发展,最终导致中国社会从汉唐的先进走向明清的衰落。黄仁宇在描绘这些历史人物的时候,重点展示了他们在这种社会设定之下辗转腾挪。

比如张居正之后的第二任首辅申行时,一般认为他是个和事佬,老好人。作者却认为,他早已看出整个文官集团中,作为统治基础的道德要求和文关门本身的的私欲之间的相互抵触。

作者以阳和阴来说明道德与私欲的矛盾。道德礼法是阳,皇帝和百官需要通过各种象征性的仪式来维持人们对于道德的信任,从而达到上下一心的目的,bi并完成国家治理。但另一方面,大明王朝历经两百年,文官集团已经成为事实上的统治集团,文官们为了私欲进行各种争斗也是无可否认的事实。

万历皇帝了解到道德与私欲并存的过程正是从张居正死后大臣对他的弹劾开始的。万历皇帝发现这个曾经以道德教育自己,以简谱自居的首辅大臣其实私生活相当奢侈,他对于自己多年受到的要为明君的道德信条也终于坍塌。

万里皇帝还逐渐了解到,及时那些对张居正进行攻击的大臣,也并不是完全怀着纯正的目的,他们也是通过这种手段获取利益。作为皇帝表面上拥有无上的权力,但也不得不收到传统文化和文官集团的掣肘,而他并无能力改变这一局面,于是他选择了怠政的方式作为对文官集团的报复。

张居正死后被清算的原因在于他改革社会的同事,试图以权威压制私欲,最终在死后遭到反弹。申行时在了解这一问题之后调整方法,努力维持人们对于道德的信任的同事又不过分压制文官的私欲。

申行时的这种中庸和妥协的方法当然难免受到非议,人们会认为他不作为,对导致明朝覆亡的诸多隐患置之不顾。但作者却指出,在传统中国社会道德统治的设定之下,供申行时选择的空间不存在了。

另一个代表人是以清廉正直的名声享誉本朝的海瑞。他所提倡的社会治理的方法乃是以残酷的手段,如朱元璋时期的剥皮之刑,惩治道德败坏,贪污腐败者。立足点仍然是惩治私欲,维护道德。即使是万历皇帝也认为他的主张过于怪癖而认为他冥顽不化,最终海瑞落寞的死在任上。

军事领域的情形十分类似。明朝立国以来,为防止武将作乱,始终以文职为尊,打压排挤武将。戚继光所进行的军事改革也仅仅是局限在抗击倭寇的前线部队之中,而无法触动更大的军事集团。

思想界的代表人物李贽同样如此。李贽力图突破程朱理学的限制,提出人可以有私欲的观点。但是最终仍然不被认可,并在信仰程朱理学的士绅们的迫害之下入狱,最终自刎。

在作者看来,海瑞,戚继光,李贽都是因为受到传统文化的掣肘而得不到有意义的发展的人。

本书作者黄仁宇原本是国民党的军官,二战结束后进入美国密歇根大学跟随著名学者余英时学习历史,1964年获得密歇根大学历史学博士学位。本书1976年即已成稿,然而因为研究方法别出心裁,一直到1981年才在耶鲁大学出版社的支持下出版。

这本书原作为英文,后经作者翻译为中文,但行文乃仍然保留了许多英语文章的特色。

Building Microservices Note: Integration

What is Microservices Integration ?

How one microservice can talk with another? In general, the following technologies could be used: shared database, RPC, and REST. But how do we pick up the right one?

The following are general answers to the questions:

  • Avoid breaking changes.

When we add a change on the server side, the client side should not be impacted unless necessary.

  • Keep your APIs technology agnostic

This is to avoid integration technology that dictates what technology stacks we can use to implement the micro services.

  • Make your service simple for consumers

Make it easy for the consumers to user the services.

  • Hide internal implementation details

Don’t have the consumers bound to the internal implementation.

With this guideline, let’s take a look at available options.

Integration technology

Shared Database

The most common form of integration is database(DB) integration: if other services want to retrieve or update the information from another service, they reach into the database.

This integration pattern definitely breaks many of the guidelines we set put:

  • It allows the external parties to view and bind to internal implementation details.
  • The customers are tied to a specific technology choice. For instance, if we decided to use Postgres, the consumer has to find a way to integrate with Postgres.
  • It would be very difficult to change the logic, the logic of parsing the data must be spreader across all consumers.

So in sum, shared database is never a good choice for micro service integration.

Remote Procedure Call

Remote Procedure Call(RPC) refers to the technique of making a local call and having it execute on a remote service somewhere.

The common used PRC techniques includes SOAP, Thrift, Protocol Buffers. They support separate interface definition, and client/server stub generation based on the definition.

Some of the technique bind to a specific networking protocol, while some allows you to use different type of protocols. For example, gRPC utilizes Protocol Buffer and HTTP2.

Some RPC mechanism are heavily tied to a specific platform, but some other mechanisms for example Thrift and protocol buffer support multiple languages.

So, what’s the major downside of RPC calls? The problem is, Local Calls are not like Remote Calls. The consumers often forget about one thing: the network is not reliable. The client needs to keep in mind that the remote server could be down, be slow or the request could be lost and handle these situations properly.

REST

Representational State Transfer(REST) is another technique. The most important concept of REST is resources. The REST service creates different representations of this resource on request.

REST and HTTP

REST as a design pattern does not talk about underlying protocols, although it is most commonly used over HTTP. The major reason is HTTP itself defines some useful capabilities that works very well with REST style, for example, the HTTP verbs: GET, POST, and PUT, and HTTP error codes.

There are, of course, downside of REST over HTTP. For server to service communication, if extremely low latency or small message size is important, HTTP might not be a good choice, as the message header can be big. TCP/UDP might be a better choice in these case.

Data Interchange

REST support many formats of data interchange framework, the most comply used one are JSON and XML. Application data are converted into JSON/XML format, and then transmitted to the other service.

JSON V.S. XML

Both JSON and XML are human readable and machine readable.

  • XML supprots store the metadata information with the tag.

For example, the type of the field, while JSON has to encode these metadata as an object and associate it with the data.

  • XML supports link while JSON does not.

Xlink is used to create hyperlink in XML documents, with Xlink, the link content can be defined outside the linked files. While JSON is purely data based, and does not support anything similar. For python, the objects has to be concretely rendered in multiple places even though they share the same content.

  • JSON is significantly less verbose than XML.
  • JSON supports array.

This make it easy to be mapped to the data structure in the programming languages, for example, array, list, hash map etc. . For example, JSON is directly interchangeable with python dict. JSON objects can be easily parsed and manipulated in almost all programming languages.

《自私的基因》书评

对于流行的东西我总有意无意保持一定的距离,《自私的基因》也属于此类。这本书在我上大学时就已十分流行,我在许多场合、听许多人谈起过这本书,但一直没有下定决心去读。大概因为这个名字过于标新立异,透漏着一种想要以奇特的理论来震撼读者的刻意。最近重点在读人类学的书,于是终于决心翻出来认真读一读。

这本书主要从基因的自私性出来解释个体和群体中的行为,尤其是最受传统进化论困扰的利他的行为

简单的说,这本书的理论框架是这样的:

  1. 基因是进化的基本单位,所谓基因是控制某个生物形状或特性的染色体片段。
    个体或者群体都不是进化的基本单位。
  2. 基因进化的竞争对手是控制同一个性状或特性的等位基因。
  3. 基因的进化的目标是为了提高自己在整个等位基因库中的比例。
  4. 基因进化的一切目标都是以此为出发点,是完全利己的。
  5. 基因进化主要通过控制个体的形状或特性来实现。
  6. 不同的形状或者遗传特性最终会为个体带来不同的繁殖机会,从而影响控制这一特性的基因在后代中的比例。
  7. 基因和等位基因之间的竞争会最终达到一个稳定状态,各个等位基因在基因库中所占的比例保持稳定。
  8. 带来这个稳定状态的策略是进化稳定策略(evolution stable strategy),稳定策略是不同策略博弈的产物。
  9. 基因的竞争并不是单一的,而是相互影响的,最后可能造成不同基因相互配合的效果。
  10. 生物的行为包括利他的行为都可以用基因的自私性来解释。

这本书最核心的概念是ESS,也就是进化稳定策略。ESS的特别之处在于,它从博弈论的角度来研究带来不同竞争策略的基因是如何相互影响并最终达成平衡的。作者几乎花了一半的篇幅在讲解如何使用ESS这个概念解释生物的行为,其中着墨最多也最有趣的是生物的性选择策略,这里可以简要介绍一下。
 

生物性选择的基础是两性生育和抚养后代的成本的不对等。这种不对等主要体现在两性的配子的不对等(出现这种不对等的原因作者在书中有介绍)以及孕育后代的不对等上。雌性和雄性在博弈过程中的优化目标都是尽可能多地繁殖带有自己基因的后代,然而不对等的生殖成本带来了雄性和雌性在性选择策略上的差异。作者归纳一般有两种性选择的策略,幸福家庭类以及大丈夫类的。

幸福家庭类的策略中,雌性选择延长决定时间来考验男性的忠诚程度,进而推断出其照料后代的机会和能力,雄性选择通过大量前期投入来证明自己付出的意愿和能力。这两种类型之外还有两个变动因素是浪荡的雌性和薄情雄性,前者会和任何后代交配但并不会养育后代,后者会在交配后抛弃雌性和幼子。浪荡的雌性会有更多的机会和诚实的雄性集合,但是随着浪荡雌性比例在后代中的提高,薄情雄性的机会也随着增大了, 最后养育成本还是会到浪荡雌性一方,而对着薄情雄性的增多,忠诚雌性的优势就会增加,比起被抛弃,不产生交配的净收益更大,因此忠诚雌性对浪荡雌性更具有优势。而对着忠诚雌性比例的增加,薄情雄性的数量就会相应下降了,因为无法找到足够进行交配的雌性。这四种性选择的个体的比例就会在这样的动态博弈之中到达平衡。
 

当然作者还用自私基因的理论介绍了更多生物的行为,比如在有些鱼类当中,主要依靠雄性照顾后代。这主要是因为雌性会先排出卵子并逃走,从而将照料后代的任务转嫁到雄性一方。作者通过这些例子有效的证明了自私的基因这个理论所具有的强大说服力。用一个简洁有力的理论对诸多现象进行剖析本身是十分有趣的,更多的例子以后有机会再单独拿出来介绍。 

作者还花费了很多篇幅批判群体进化论。所谓群体进化论是认为生物的利他行为是出于对整个群体或者物种的利益的考虑,也即牺牲自己造福种群的理论。作者认为,这一概念的根源其一是人们将进化的单位上升到了群体,其二是因为这种理论契合了人类的道德感召的需求,即对牺牲自我的利益以换取更多人利益的这种利他主义的感召(这在许多宗教中非常常见)。但这个理论的根源问题在于,让生物在长期物种的利益和短期个体的利益之间选择前者无疑是不现实的,另一方面,种群进化的理论在很多例子当中是有解释力不足的问题的。

在最后一章中,作者还提出了一个文化觅母(meme)的概念。meme指人类的文化观念。meme的发展目标与基因类似,就是最大程度上的复制自己。但是meme的利益并不总是和基因的利益相同。比如有越来越多的家庭选择不生育孩子,这种观念就与基因传播自己到下一代的利益相悖。但平衡指出在于,如果二者相悖太远,meme传播的基础人类载体本身就会减少,从而降低自己被传播的机会。 

人类行为的特殊性在于,除了受到遗传的影响,还会受到文化的影响。在本书中,作者一直强调,从进化的观点看,生物只是运载和复制基因的载体。同样的,人也可以看作是文化观念的载体,文化不断发生,发展,传播,演变,和基因的演化和气相似。而这种相似性正是meme这个概念所想要揭示的规律。

 
当然,自私基因的理论如此强大,以至于有人会产生人类的高尚行为背后不过是基因的意志这种感觉。实际上,在很多年前初次知道这种理论的时候我也感到有些困惑:这和历史上的种种还原论何其相似,人类的行为被还原到了化学物理层面,现在又被还原到了生物层面,那么人类的这些高尚的可贵的行为真的包含了值得赞颂的东西吗?

我的回答是:人具有自由意志。尽管人类的行为强烈的受到基因的影响甚至控制,但是人类有足够的自由意志可以克服甚至消除这种影响,而这才是人类最可贵的地方。父母对子女的爱固然包含着基因的自私性这一根源,但是我们无法否认他们事实上的付出、奉献和关爱,理解了这些才会更加感到人的可贵。 

Python Notes: Global Interpreter Lock

Why Python use GIL

Python uses reference count for memory management. Each objects in python has a reference count variables that keep track of the number of reference to the object. When the reference count goes back to 0, Python would release this object from memory.

However, in multi threading scenario, multiple thread might access the same object, and object reference count could be changed incorrectly in race conditions. Then objects that should be released could still stay in memory and worst case, objects that should not be release are incorrectly released.

To solve this problem, python introduced GIL, which is a global lock in python interpreter level. The rules is that, any python code has to acquire this lock to be executed. You might ask why not add one lock to each objects? This could result in deadlock.

In this way, python code guarantees that only one thread would be able to change the object reference count.

Problem of GIL

The GIL solution, however has problems in that Python code would not be able to utilize multi CPUs. If your code is CPU intensive, python multi-thread would not help you at all. However, if you program is not CPU intensive, but I/O intensive, for example, network application, Python thread is still a good choice.

Solution to this problem?

Are there solutions to the problem? Yes, there are. Python community has tries many times to solve this problem. Python GIL is not really tie to python language it self, it ties to Python interpreter it self. So, as long as we change the underlying python interpreter, python could support multithread. For example, Jython, is implemented in Java.

However, another important reason why Python GIL is not removed is that python has many extended libraries that are writing in C. Those libraries works well with Python in that they don’t need to worry about multi-thread models, the GIL model is really easy to integrate. Moving those libraries to other interpreters are hard works.

Another solution is to use multiprocess instead of multithread. Python has good designed libraries that supports multiprocess. However, process management would have more overhead than thread management for operating system, which means the performance of multiprocess programs are worse than multithreads.

Python Notes: Decorator

By definition, a decorator is a function that takes another function and extends the behavior of the latter function without explicitly modifying it. Built-in decorators such as @staticmethod, @classmethod, and @property work in the same way.

How decorator works? Let's take a look at the following example:

def my_decorator(some_func):
    def wrapper():
        some_func()
        print("Some function is being called.")

    return wrapper

def another_func():
    print("Another function is being called.")

foo = my_decorator(another_func)

foo()

You would see the following print on the screen:

"Another function is being called."
"Some function is being called."

As you can see, we pass some_func into a closure, and do something before or after calling this function without modifying its original behavior, and we return the function. As we already learned, python functions are just like other python objects, they are first class objects. The returned function could be called just as any other functions.

@decorator

The above example is already very similar to decorator. The difference is that decorator often comes with a @ symbol. This is an example of python syntax sugar, which often refers to syntax in a programming language that aims to make the things easy to read or to express. For example, the following is an example of a decorator:

@my_decorator
def another_func():
    print("Another function is being called.")

Decorator that takes any argument

In python, we can use *args and **kargs to represent arbitrary arguments. The following example shows how to take arbitrary arguments in a decorator:

def proxy(func):
    def wrapper(*args, **kargs):
        return func(*args, **kargs)
    return wrapper

Decorator with parameters

Sometimes we want the decorator to take parameters, for example, we should implement it in this way:

def decorator(argument):
    def real_decorator(function):
        def wrapper(*args, **kwargs):
            do_something_with_argument(argument)
            result = function(*args, **kwargs)
        return wrapper
    return real_decorator

Decorator tips

One practical tips when defining decorator is to use the functoolss.wraps, this function would keep all the meta data information of the original functions, including the function signature and docstring information.

import functools

def uppercase(func):
    @functools.wraps(func)
    def warpper():
        return func()
    return wrapper

Python Notes: function as first class object

Per history of python blog, everything in python are first class objects, that means all objects that could be named in the language (e.g., integers, strings, functions, classes, modules, methods, etc.) to have equal status. Th:at is, they can be assigned to variables, placed in lists, stored in dictionaries, passed as arguments, and so forth..

Essentially, functions return a value based on the given arguments. In Python, functions are first-class objects as well. This means that functions can be passed around, and used as arguments, just like any other value (e.g, string, int, float).

Internally, python use a common C data structure that are used everywhere in the interpreter to represent all objects, either it is a python function or a integer.

However, when it comes to python function as first class, there are subtle things to think about when doing design.

Think about the following function definition:

class A:
    def __init__(self, x):
        self.x = x

    def foo(self, bar):
        print self.x, bar

What would happen if you assign A.foo to a variable: b = A.foo. The first argument of the function would have to be the instance itself. To handle this problem, python 2 returns a unbound method, which is a warper around the original function, but it restrict that the first argument of the function has to be the object instance: a = A(), b(a). In python 3, however, this restriction is removed as the author found this is not very useful.

Let’s think about the second condition, when you have a instance of a class: a = A(1), b = a.foo. In this case, python would return a bound method which is a thin wrapper around the original function. Bound method stores the instance as a internal object and this object would be the default first argument when calling this function.

马尔萨斯和《人口原理》

马尔萨斯是十八世纪英国的人口学家和政治经济学家。他最被广为人知的作品是《人口论》,而其中又以马尔萨斯人口陷阱这一概念最为人所熟知。

马尔萨斯陷阱

马尔萨斯人口陷阱(Malthusian Trap)是说:

  • 在没有限制的情况下,人口会呈现指数型增长
  • 食物只会呈现现行增长
  • 人口的增长一定会超过食物增长,从而导致食物不足

马尔萨斯认为,人类有两种方式会避免或者延缓这一情况的出现:

  • 有意识的晚婚晚育。
  • 缩减人类寿命的时间,比如战争,瘟疫,饥荒等。

需要进一步阐明的事,马尔萨斯所说的极限,是说在系统达到均衡的条件下,处在社会最底层的那部分人永远只能生活在勉强温饱的生存线上。至于处于社会底层的人口数量有多大,这是随着社会制度不同而不同的。

马尔萨斯为什么会认为人口数量会有极限呢?因为存在着生产的极限,在极限附近,生产投入的回报是递减的,也就是说,随着投入的增加,单位产出实际上是减少的。为什么我们没有陷入马尔萨斯所说的陷阱当中呢?因为技术的进步,我们不断发现更新更有效的生产方法,使得生产的边际回报是递增的。另一方面,主要是因为现代发达国家的生育水平逐渐下降,有些国家甚至到了低于代际更替水平一下,带来实际人口的减少。这主要是城市化造成的,城市化带来和生育孩子机会成本的提高:妇女的劳动价值越来越高,为了生育小孩儿放弃的成本也就会越来越高。另一方面是,多生孩子意味着需要稀释在每个孩子身上的投入,从而可能降低生育质量。

工资铁律

从马尔萨斯定律推论出来的一个理论是工资铁律。工资铁律是说,对于非技术工人,实物工资在长期将永远倾向于接近仅足够维持工人最低生活所需的水平。工资铁律描述的启示是马尔萨斯的模型出于边界时的情形,如果工资继续降低,工人将无法维持生活,工人数量将停止增加,如果工资升高,工人数量将会上升,压低劳动成本,从而使得工资回到最低水平。但是我们并未看到工资铁律的实际出现,这是因为,新的技术,投资导致市场对于劳动力需求的增大,避免了因为劳工过剩而带来的工资降低。

马尔萨斯弹簧

马尔萨斯理论的另一个衍生是马尔萨斯弹簧。马尔萨斯弹簧模型是用于解释文明诞生所需要的剩余如何发生。我们都知道,因为有这些剩余,一个社会才会有能力供养不进行实际劳作的人口,从而使他们有机会发展科技,文学,艺术等等。但是为什么会产生这些剩余呢?常见的误区是认为这是由于技术带来的生产力的提高,导致实际产出多于供养人口所需要的实物数量,于是便产生了剩余。但是根据马尔萨斯的理论,人口数量总是会趋近于极限水平,也就是剩余为零的水平,这样的人口增长只需要几代人便可以实现。但是为何这种情况没有发生呢?一个重要原因就是税赋,因为税赋的存在,劳动人群的产出被拿走一部分,使得实际的粮食产出降低,人口也就不会增加到极限水平。这种因为税赋带来的对于人口的抑制作用便称为马尔萨斯弹簧。

不得不说这种解释是包含着很多洞见的,如果从税赋的最终效果来看,它们确实被用来供养一个广大的上层阶级,从而促进了社会的发展。但是另一方面,实际非劳动人口之所以可以生存下来并将它们的技艺发展提高,也是因为他们的产品实际上是被需要的。比如手工艺人制作的农具,比如喜剧演员的表演,都是劳动人群愿意购买的产品和服务,是市场价值,而不是强制的税赋供养了这些非劳动人口。单着并不意味着马尔萨斯弹簧的实效,实际上,马尔萨斯的理论强调的长期的趋势。马尔萨斯认为,从长期看,人们的生活水平总是因为实际人口的增加而降低的,而生活水平的降低意味着购买能力的降低,供养非劳动人口的市场缩小,文明的发展因此会被抑制。因此可以说税赋确实是长期一直人口增长的有效弹簧。

马尔萨斯与进化论

马尔萨斯的理论也启发了达尔文发明生物进化理论。生物进化理论要论证的是生物是通过不断在适应环境的过程中进化而来,而这是结果,生物进化的动因在于生存压力,其中最重要的压力之一是食物资源的压力,因为没有足够的食物资源,生物群体内部同样要发生激烈竞争。

马尔萨斯在起人口论的第十八章中阐明了人口压力对于文明发展的推动作用。马尔萨斯认为,正因为人口永远会朝向极限的状态发展,资源永远都是不足的,因此富有才智的人们才会愿意去努力发展自己。如果谁也不想在社会的阶梯上往上爬,谁也不担心会从社会的阶梯上摔落下来,如果勤劳得不到奖励,懒惰得不到惩罚,中产阶级就肯定不是现在这种样子了。 了解到奋斗这个过程的无可避免,或许是我们在奋斗路上的一个小小安慰。