Quantcast
Channel: 懒得折腾
Viewing all 764 articles
Browse latest View live

Swift 中 10 个震惊小伙伴的单行代码

$
0
0

作者:uraimo,原文链接,原文日期:2016-01-06
译者:bestswifter;校对:numbbbbb;定稿:小锅

几年前,函数式编程的复兴正值巅峰,一篇介绍 Scala 中 10 个单行函数式代码的博文在网上走红。很快地,一系列使用其他语言实现这些单行代码的文章也随之出现,比如 HaskellRubyGroovyClojurePythonC#点击预览,F#CoffeeScript

我们永远无法得知有多少人在社交聚会中对这些单行代码留下了深刻的印象,但根据我的猜测,越复杂的例子越能激励我们学习更多函数式编程的知识,至少对外行人来说是这样。

通过使用单行代码完成同样的 10 个练习,我们来看看 Swift 和其他语言之间的较量。在这个过程中,你也许还能学到一些有趣的东西(参见 #6 和 #10)。

你可以从 GitHubzipped 上下载本文的 playground。

1 将数组中每个元素的值乘以 2

第一个例子中没什么干货,我们都知道只要使用 map 函数就可以简单地解决问题:


(1...1024).map{$0 * 2}

2 求一组数字的和

这个问题可以通过使用 reduce 方法和加号运算符解决,这是因为加号运算符实际上也是一个函数。不过这个解法是非常显而易见的,待会儿我们会看到 reduce 方法更具有创造力的使用。


(1...1024).reduce(0,combine: +)

3 证明字符串中含有某个单词

我们使用 filter 方法判断一条推文中是否至少含有一个被选中的关键字:


let words = ["Swift","iOS","cocoa","OSX","tvOS"]
let tweet = "This is an example tweet larking about Swift"

let valid = !words.filter({tweet.containsString($0)}).isEmpty
valid //true

更新@oisdk 建议这样写会更好:


words.contains(tweet.containsString)

这种写法更加简练。另外,也可以这样写:


tweet.characters
  .split(" ")
  .lazy
  .map(String.init)
  .contains(Set(words).contains)

4 读取一个文件

和其他语言不同,Swift 不能使用内建的函数读取文件,并把每一行存放到数组中。不过我们可以结合 splitmap 方法写一段简短的代码,这样就无需使用 for 循环:


let path = NSBundle.mainBundle().pathForResource("test", ofType: "txt")

let lines = try? String(contentsOfFile: path!).characters.split{$0 == "\n"}.map(String.init)
if let lines=lines {
    lines[0] // O! for a Muse of fire, that would ascend
    lines[1] // The brightest heaven of invention!
    lines[2] // A kingdom for a stage, princes to act
    lines[3] // And monarchs to behold the swelling scene.
}

最后一步使用 map 函数和字符串的构造方法,将数组中的每个元素从字符数组(characters)转换为字符串。

5 祝你生日快乐

这段代码会将“祝你生日快乐”这首歌的歌词输出到控制台中,它在一段区间内简单的使用了 map 函数,同时也用到了三元运算符。


let name = "uraimo"
(1...4).forEach{print("Happy Birthday " + (($0 == 3) ? "dear \(name)":"to You"))}

6 数组过滤

假设我们需要使用一个给定的过滤函数将一个序列(sequence)分割为两部分。很多语言除了有常规的mapflatMapreducefilter 等函数外,还有一个 partitionBy 函数恰好可以完成这个需求。正如你所知,Swift 没有类似的函数(我们不想在这里使用 NSArray 中的函数,并通过 NSPredicate 实现过滤功能)。

所以,我们可以通过拓展 SequenceType,并为它添加 partitionBy 函数来解决这个问题。我们使用这个函数将整数数组分割为两部分:


extension SequenceType{
    typealias Element = Self.Generator.Element

    func partitionBy(fu: (Element)->Bool)->([Element],[Element]){
        var first=[Element]()
        var second=[Element]()
        for el in self {
            if fu(el) {
                first.append(el)
            }else{
                second.append(el)
            }
        }
        return (first,second)
    }
}

let part = [82, 58, 76, 49, 88, 90].partitionBy{$0 < 60}
part // ([58, 49], [82, 76, 88, 90])

实际上,这不是单行代码,而且使用了命令式的解法。能不能使用 filter 对它略作改进呢?


extension SequenceType{

    func anotherPartitionBy(fu: (Self.Generator.Element)->Bool)->([Self.Generator.Element],[Self.Generator.Element]){
        return (self.filter(fu),self.filter({!fu($0)}))
    }
}

let part2 = [82, 58, 76, 49, 88, 90].anotherPartitionBy{$0 < 60}
part2 // ([58, 49], [82, 76, 88, 90])

<!–enclosing function 这边不太理解–>

这种解法略好一些,但是他遍历了序列两次。而且为了用单行代码实现,我们删除了闭合函数,这会导致很多重复的内容(过滤函数和数组会在两处被用到)。

能不能只用单个数据流就对原来的序列进行转换,把两个部分分别存入一个元组中呢?答案是是可以的,使用 reduce 方法:


var part3 = [82, 58, 76, 49, 88, 90].reduce( ([],[]), combine: {
    (a:([Int],[Int]),n:Int) -> ([Int],[Int]) in
    (n<60) ? (a.0+[n],a.1) : (a.0,a.1+[n])
})
part3 // ([58, 49], [82, 76, 88, 90])

这里我们创建了一个用于保存结果的元组,它包含两个部分。然后依次取出原来序列中的元素,根据过滤结果将它放到第一个或第二个部分中。

我们终于用真正的单行代码解决了这个问题。不过有一点需要注意,我们使用 append 方法来构造两个部分的数组,所以这实际上比前两种实现慢一些。

7 获取并解析 XML 格式的网络服务

上述的某些语言不需要依赖外部的库,而且默认有不止一种方案可以处理 XML 格式的数据(比如 Scala 自身就可以将 XML 解析成对象,尽管实现方法比较笨拙),但是 (Swift 的)Foundation 库仅提供了 SAX 解析器,叫做 NSXMLParser。你也许已经猜到了:我们不打算使用这个。

在这种情况下,我们可以选择一些开源的库。这些库有的用 C 实现,有的用 Objective-C 实现,还有的是纯 Swift 实现。

这次,我们打算使用纯 Swift 实现的库:AEXML


let xmlDoc = try? AEXMLDocument(xmlData: NSData(contentsOfURL: NSURL(string:"https://www.ibiblio.org/xml/examples/shakespeare/hen_v.xml")!)!)

if let xmlDoc=xmlDoc {
    var prologue = xmlDoc.root.children[6]["PROLOGUE"]["SPEECH"]
    prologue.children[1].stringValue // Now all the youth of England are on fire,
    prologue.children[2].stringValue // And silken dalliance in the wardrobe lies:
    prologue.children[3].stringValue // Now thrive the armourers, and honour's thought
    prologue.children[4].stringValue // Reigns solely in the breast of every man:
    prologue.children[5].stringValue // They sell the pasture now to buy the horse,
}

8 找到数组中最小(或最大)的元素

我们有多种方式求出 sequence 中的最大和最小值,其中一种方式是使用 minElementmaxElement 函数:


//Find the minimum of an array of Ints
[10,-22,753,55,137,-1,-279,1034,77].sort().first
[10,-22,753,55,137,-1,-279,1034,77].reduce(Int.max, combine: min)
[10,-22,753,55,137,-1,-279,1034,77].minElement()

//Find the maximum of an array of Ints
[10,-22,753,55,137,-1,-279,1034,77].sort().last
[10,-22,753,55,137,-1,-279,1034,77].reduce(Int.min, combine: max)
[10,-22,753,55,137,-1,-279,1034,77].maxElement()

9 并行处理

某些语言支持用简单透明的方式允许对序列的并行处理,比如使用 mapflatMap 这样的函数。这使用了底层的线程池,可以加速多个依次执行但又彼此独立的操作。

Swift 还不具备这样的特性,但我们可以用 GCD 实现:

http://moreindirection.blogspot.it/2015/07/gcd-and-parallel-collections-in-swift.html

10 埃拉托色尼选筛法

古老而优秀的埃拉托色尼选筛法被用于找到所有小于给定的上限 n 的质数。

首先将所有小于 n 的整数都放入一个序列(sequence)中,这个算法会移除每个数字的倍数,直到剩下的所有数字都是质数。为了加快执行速度,我们其实不必检查每一个数字的倍数,当检查到 n 的平方根时就可以停止。

基于以上定义,最初的实现可能是这样的:


var n = 50
var primes = Set(2...n)

(2...Int(sqrt(Double(n)))).forEach{primes.subtractInPlace((2*$0).stride(through:n, by:$0))}
primes.sort()

在外层的区间里,我们遍历每一个需要检查的数字。对于每一个数字,我们使用 stride(through:Int by:Int) 函数计算出由它的倍数构成的序列。最初,我们用所有 2 到 n 的整数构造了一个集合(Set),然后从集合中减掉每一个生成的序列中的元素。

不过正如你所见,为了真正的删除掉这些倍数,我们使用了一个外部的可变集合,这会带来副作用。

我们总是应该尝试消除副作用,所以我们先计算所有的子序列,然后调用 flatMap 方法将其中所有的元素展开,存放到单个数组中,最后再从原始的集合中删除这些整数。


var sameprimes = Set(2...n)

sameprimes.subtractInPlace((2...Int(sqrt(Double(n))))
                           .flatMap{ (2*$0).stride(through:n, by:$0)})
sameprimes.sort()

这种写法更加清楚,它也是 使用 flatMap 展开嵌套数组 这篇文章很好的一个例子。

11 福利:使用析构交换元组中的值

既然是福利,自然并非每个人都知道这一点。和其他具有元组类型的语言一样,Swift 的元组可以被用来交换两个变量的值,代码很简洁:


var a=1,b=2

(a,b) = (b,a)
a //2
b //1

以上就是全部内容,正如我们预料的那样,Swift 和其他语言一样富有表现力。

你还有其他用 Swift 实现的有趣的单行代码想与我们分享么?如果有,请让我知道

感谢 @oisdk 审核这篇文章。

如果你想发表评论,请在 Twitter 上和我联系。



React Native开发技术周报Issue#07

$
0
0

React Native开发技术周报Issue#07

尊重版权,未经授权不得转载出处:http://www.lcode.org

本周报来自江清清的技术专栏,欢迎微信关注公共号:codedev123.精彩技术文章第一时间推送!

说在前面的话:React Native开发技术周报,主要会涉及React Native最新资讯,React Native教程,技术开发文章,开源项目,工具,视频等等。今天是我们的第七期,同时各位朋友有优秀的有关React Native技术开发文章可以发给我。

React Native交流4群:458982758

(一).资讯

1.React Native最佳学习模版- F8 App开源了

本周大家关注的对象就是F8大会啦,同样F8大会结束之后,官方F8 APP开源了,对大家来讲这个一个非常好的消息啦。界面和体验超级美观啦,小伙伴们都惊呆啦~赶紧去学习吧。

2.Facebook开发F8 2016 App官方教程的中文版。 原官网: http://makeitopen.com/

Facebook 在 F8 开发者大会上宣布他们用 React Native 开发了 F8 开发者大会的官方应用。他们不仅仅开发了应用(可从 App Store 和 Google Play 下载),还设置了一个官方网站:http://makeitopen.com/ ,开源了官方应用的代码,并且还写了如何开发的教程。这将是开发者学习 React Native 非常好的教程,因此我们将其翻译为中文,提供给国内开发者。

3.FaceBook   React Native教程

该为翻译版本,正在更新翻译,翻译官方的教程,还是非常不错的。秋百万大神

(二).技术文章

1.基于 Facebook Redex 实现 Android APK 的压缩和优化

最近 Facebook 开源了一个名为 Redex[1] 的工具包,专门用于 Android 字节码的优化,经过 Redex 转换后的 APK,体积变得更小,运行速度变得更快。Redex 基于管道的方式来优化 Android 的 .dex 文件,一个源 .dex 文件通过管道进行一系列的自定义转换后,将得到一个优化的 .dex 文件。本文将带大家简单快速的了解 Redex 是什么,以及它的基本原理和使用方法,

2.webpack实践最后一篇

这应该是目前这个阶段最后一篇关于webpack的实践经验,也许你会学习到该用怎样的思想去使用webpack。

3.React组件生命周期小结

该文章很好的介绍了React组件的相关生命周期用法,在进行React Native开发过程中非常有用啦。

4.Redux是如何工作的 (一)

凡是用reactjs开发的项目,但凡规模稍微大一些,都很可能要引入redux来管理组件状态的变迁和组件彼此之间的通信,权威的解释和说明当然是官方的这篇文章,但是,但是,但是,这篇长文处处透露着一种玄妙而不可言说的味道,处处是一些principle,best practice,never,absolutely,you should……的字眼,到处是强调,加粗的段落,一些模糊的store,action,reducer之类的抽象用词,我尝试着写篇小文来记录自己对Redux的学习理解过程。

5.你好 ES2015-介绍ES2015的基本使用方法

ES2015 是新版的 JavaScript,Node.js 已经完全支持,浏览器端可以用 Babel 库编译。运行本文的示例代码,可以用 JSBin 环境,也可以结合原文中的测试题检测学习效果。

6.React Native on the Universal Windows Platform(UWP平台支持React Native啦)-英文原版

7.Win10 UWP 再支持 React Native 开源框架

看起来React Native真心大有作为了~

8.React JS新手教程

系列教程

9.[英] ECMAScript 6 里面的私有变量

在 ES6 里面怎样来申明并使用一个私有变量呢,来看看这个有趣的文章。

10. 构建 F8 2016 App 第一部分:开发计划

这是为了介绍 React Native 和它的开源生态的一个系列教程,我们将以构建 F8 2016 开发者大会官方应用的 iOS 和 Android 版为主题。在第一部分,我们将介绍我们是如何计划的,在后面的部分,我们将分享示例代码,讨论多平台设计需要考虑的事情,分析应用的数据层,最后解释我们所选择的测试策略。

11.两周 React Native 开发小结(传说中的从入门到放弃?)

将原有的 Swift 代码改成 React Native 是个不小的动作,我们选择了一些对主要功能影响不大的页面定点重构,主要考虑到 React Native 的几个优点:①.跳过 App Store 审核,远程更新代码,提高迭代频率和效率;②.减少编译时间,开发效率更高;③.组件化开发,更高的复用率;④.相对其它 Hybrid 方案,React Native 性能更好,用户体验更接近原生。

经过我一个人两周的折腾,发现这些优势并不能在我们的 App 里最大化。最后我把所有 React Native 写的代码全部删除,花了两天时间用 Swift 重写了一遍。

12.FaceBook   React Native教程

该为翻译版本,正在更新翻译,翻译官方的教程,还是非常不错的。秋百万大神

13.2016/04/18 React Native 开源一年的总结

该文章翻译自Facebook工程团队的官方博客,React Native: A year in review,本文分别从 RN 起源,项目过去一年在FB内部的发展,在业界的广泛使用和生态圈的快速建立,在 Github 上的开源协作,核心团队对 RN 的未来展望等进行一一讲述,来吧看看 RN 的传奇之路

14.[译]推荐5个值得学习React Native的开源项目

读源码是最好也是最有效的提升自身编码能力的方式,特别是当该项技术比较新然后它的标准还在不停改进的时候。ReactNatve就是其中一个。它的API随着每次发布还在持续的迭代 ,你会碰到很多需要选择的工具然后除了一些简单的HelloWorld教程,稍微深入些的教程比较少。于是,我们还是来读读别人的开源项目源码吧,

15.图解redux和react的关系

16.React Native 0.23 iOS: 体验灵活的flexbox布局UI

17.Webpack 一探究竟

Webpack 的两个主要思想:

①.所有的一切都是模块(module) —— 就像 JS 可以模块化一样,所有的一切 (CSS, Images, HTML) 都可以是模块。就是这样,你可以 require(‘myjsfile.js’) 或者 require(‘myCSSfile.css’)。这意味着我们可以把任何部件分割成更小的可管理的模块用来复用等等。

②.按需加载 通常来说模块打包只能将你所有的模块打包成单个大的”bundle.js”文件。但是在现实世界中,”bundle.js”可能达到 10MB-15MB 导致过长的加载时间。所以 Webpack 有专门的功能用来分割你的代码并且生成多个打包文件,同样也能异步加载部分模块,所以你只需要”按需加载”即可。

18.React Native 蛮荒开发生存指南

React Native虽然已经得到了很多支持,但坑仍然很多,在短期不会消失,因此你应该了解RN生存策略,避免掉坑出不来,或者从入门到放弃。本文就介绍了RN的生存指南,包括学习资源和遇到问题的解决之道。

(三).开源项目

1.React Native 实例 – 房产搜索App

React Native 开发已经初见端倪, 可以完成最基本的功能. 通过开发一些简单的应用, 可以更加熟练的掌握 RN 的知识. 本文介绍非常简单的一款房产搜索的App, 通过调用公开的搜索服务, 把网络的数据展示在应用中. 通过代码更多的了解 RN 的特性.

2.React Native构建的干货集中营客户端-very 因垂思挺

干活集中营,大家懂的,干货确实很多,当然还有很多妹纸~嘎嘎,这一款APP Very 因垂思挺。

3.使用ES6来编写React-基础到提高

4.基于 React Native 的 Dota 视频 APP

效果还是挺不错的,视频客户端哦~

(四).工具

1.Visual Studio Code 1.0正式版本发布啦

如果有用VSCode进行React Native开发的童鞋们有福了,VSCode V1.0正式版本已经发布了。同时也提供了智能提醒和调试相关插件。

尊重原创,未经授权不得转载:From 江清清的技术专栏(http://www.lcode.org) 侵权必究!

关注订阅号(codedev123),每天分享移动开发技术(Android/IOS),React/React Native,项目管理以及博客文章!(关注,第一时间推送精彩文章)


Rotate Gauge Needle in D3

$
0
0

Rotate Gauge Needle in D3

Sep 27th, 2013 | Comments

If you want to make a gauge chart in S3, you’ll need a needle on your gauge. It’s not hard to draw a triangle, but here’s the extra work to rotate it.

D3 Gauge Chart

The Gauge Chart

I’m not sure what you call this kind of chart, but I call it a gauge. It pretty much looks like a speedometer or a pressure gauge. I’m sure after seeing one, you want to make one. I’m not going to cover the arc building. It’s pretty easy to build a d3 arc.

The Components

In my case, I can match the design of the needle with a triangle and a circle. The circle is the base of the needle upon which the needle spins. The triangle is the pointer of the needle, which will eventually sit at the angle we specify to our graph.

The Coordinates

In svg/d3, you can redefine your coordinates by using a group. If my svg container is square, the default coordinate plane will start in the upper left-hand corner at (0,0). If I wanted to redefine (0,0) to be in the bottom center of the svg container, we could do so by positioning a group (g) so that its top left-hand corner is at that point.

We might write this:

gauge.coffee
1
2
3
4
height = # ... svg height
width = # ... svg width
needleG = svg.append('g')
  .attr('transform', "translate(#{width / 2}, #{height})")

Draw a Triangle

To draw a triangle, use an svg path. It needs a start point and 2 more points to draw lines to. In the special language of svg paths, M x y is the start point and L x y is the point to which a straight light will be drawn from the previous point.

Let’s say that we want our needle to 60px tall and 20px wide at the base. First we’ll draw it pointing straight up. Let’s draw this triangle using the needleG coordinates. In the code, I’ll call the corners of the triangle top, left, and right. The d3 code to draw this might look like:

gauge.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
needleLen = 60
needleRadius = 10

centerX = 0
centerY = 0

topX = centerX - 0
topY = centerY - needleLen

leftX = centerX - needleRadius
leftY = centerY - 0

rightX = centerX - -(needleRadius)
rightY = centerY - 0

needleG.append('path')
  .attr('d', "M #{leftX} #{leftY} L #{topX} #{topY} L #{rightX} #{rightY}")

Rotate the Triangle

Drawing a triangle pointed straight up, that is strictly parallel with the x and y access of the plane, is no problem. But a gauge that points straight up isn’t worth that much. It doesn’t measure anything. So, let’s rotate the pointer/triangle of the needle to get an actual visual display of our measurement.

Unfortunately, (but maybe you’ll have fun) you’ll have to pull out your middle school trigonometry here. I was remembering sayings I had heard once a time to figure this out (like the mysterious “SOHCAHTOA” acronym).

Percentage Input

Your input may vary, but mine starts as a percentage. If yours does not, you could convert it to a percentage. And since we’re working with a half circle, we’re just going to cut in half all our input since the rotation math is based on a circle.

Let’s say in this case our percentage is 65%. We need to convert from percentage to radians. Note that all the code for rotation angles will useradians. Here’s some conversion code:

gauge.coffee
1
2
3
4
5
6
7
8
percToDeg = (perc) ->
  perc * 360

percToRad = (perc) ->
  degToRad percToDeg perc

degToRad = (deg) ->
  deg * Math.PI / 180

SOHCAHTOA

We have to find the top, left, and right for a triangle rotated around the (0,0) point. The basic SOHCAHTOA formulas will help us find the points:

gauge.coffee
1
2
3
sin of angle = opposite / hypotenuse
cos of angle = adjacent / hypotenuse
tan of angle = opposite / adjacent

Needle trigonometry

Using these formulas, let’s update our code for finding the endpoints of the triangle:

gauge.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
needleLen = 60
needleRadius = 10
percent = .65

thetaRad = percToRad percent / 2

centerX = 0
centerY = 0

topX = centerX - needleLen * Math.cos(thetaRad)
topY = centerY - needleLen * Math.sin(thetaRad)

leftX = centerX - needleRadius * Math.cos(thetaRad - Math.PI / 2)
leftY = centerY - needleRadius * Math.sin(thetaRad - Math.PI / 2)

rightX = centerX - needleRadius * Math.cos(thetaRad + Math.PI / 2)
rightY = centerY - needleRadius * Math.sin(thetaRad + Math.PI / 2)

"M #{leftX} #{leftY} L #{topX} #{topY} L #{rightX} #{rightY}"

Note that Math.PI / 2 is a 90 degree angle. It’s used to find the angle smaller than theta for the left triangle and find the angle larger for the right triangle.

There you have it. That’s the magic. For an example of this working and some more code, see this codepen of a d3 gauge.


Particle Electron: Cellular Portable Streaming GPS

$
0
0

Particle Electron: Cellular Portable Streaming GPS

on May 2 | by

ParticleDashboard

Who doesn’t love a good cell-connected board? I sure do. And the Particle Electron gives me a whole lot more reason to love it than just having a cellular connection. It looks cool. It’s tiny. It has a TON of pins, including PWMs. It comes with a battery and easy plug-in connector. It has the headers pre-soldered on. It comes with a SIM card. It comes with a data plan.

Need I say more?

In this project, I’ll go over how to setup your Particle Electron, attach a GPS module, and stream GPS data to a web-connected dashboard. For a mere $112 and about an hour, you can have a portable, streaming GPS that’s reliable, rechargeable, and reprogrammable over-the-air.

-----------------------
Project level: Beginner (with soldering skills)
Approximate time to complete: Less than an hour
Practicality: Extreme. A portable, streaming GPS is always useful.
-----------------------

In this step-by-step tutorial, you will:

  • Setup your Electron and connect it to the Cloud
  • Attach and read from the GPS
  • Stream data from the Electron to a web service using Webhooks
  • Build a map dashboard that you can access from your browser

Make a Cellular-Connected GPS with the Particle Electron

This tutorial is part of the series, “Learning How to Build Real IoT Applications” >>


Top 10 Mobile Design Articles for the Past Month (v.May)

$
0
0

Top 10 Mobile Design Articles for the Past Month (v.May)

In this observation, we’ve compared nearly 1,000 mobile design articles posted and updated on the internet for the past month and sized down to Top 10.

It’s been a competitive month, especially with many thoughtful articles posted from the debut of new mobile designs at Instagram and Airbnb.

Hopefully, you’ll find this list useful and discover useful articles you may have missed out for the past month.

Note that Top 10 list for UI Design, UX Design, and Web Design are all separated out to make this curation more specific to mobile design.


Rank 1

Designing a New Look for Instagram, Inspired by the Community. Courtesy of Head of Design at Instagram, Ian


Rank 2

The Way We Build How rethinking the Airbnb app changed the way we approach design


Rank 3

A meticulous critique of the new Instagram logo/UI. Courtesy of Bryan Mamaril


Rank 4

The Design Details of Stripe Dashboard. Courtsey of Brian Lovin


Rank 5

The tangible benefits of designing at 1x pixel density. Courtesy of Director of Design at Shyp, Kurt Varner


Rank 6

7 Mobile Design Animations & 9 Principles that Improve User Experience.Courtesy of Yalantis and Anatoly Nesterov


Rank 7

Designing Uber for Seniors and Overcoming Poor Visibility. Courtesy William Belk and prototypr.io


Rank 8

40 Mobile App Onboarding Designs that Delight Users. Courtesy of @hongkiat @Photodoto


Rank 9

Designing Text Fields in Mobile App for a Better User Experience.


Rank 10

Designing Facebook’s Chatbot and how It could affect User Experience of the Web as we know it. Courtesy of Director of Product at Fast Company, Cliff Kuang


Bonus 1

20 Examples of 3D Touch Design. Courtesy of Inside Designmodo and Birch Nataly

v.April

If you missed Top 10 for April, follow this link.


That’s it for Mobile Design monthly Top 10. If you like our curation, you can read Top 10 daily articles personalized for your skills on our iPhone app. It’s free for anyone who wants to read great content and get better at work.

Hope you enjoyed it!


React Native开发技术周报Issue#11

$
0
0

React Native开发技术周报Issue#11-本期周报有福利

尊重版权,未经授权不得转载出处:http://www.lcode.org

本周报来自江清清的技术专栏,欢迎微信关注公共号:codedev123.精彩技术文章第一时间推送!

说在前面的话:React Native开发技术周报,主要会涉及React Native最新资讯,React Native教程,技术开发文章,开源项目,工具,视频等等。今天是我们的第十一期,同时各位朋友有优秀的有关React Native技术开发文章可以发给我。

React Native交流5群:386216878

本期周报底部有大福利….

(一).资讯

1.React Native 0.26正式版本发布

具体更新日志,大家可以点击标题查看,本版本最大特点React API需要从react包导入进来以及setBridge不要在主线程调用了。

至于0.26.1版本只是修复了几个bug而已。

2.React Native痛点解析之性能调优

本文为React Native痛点解析系列文章之二,自从React Native出世,虽然官方一直尽可能的优化其性能,为了能让其媲美原生App的速度,但是现实感觉有点不尽人意。接下来介绍下实践中遇到的一些性能问题以及优化方案。

3.ReactMix:基于HTML+JS+CSS写APP的最佳实践

携程这是要起飞的节奏~

React Native目前存在着几方面的问题:第一,React Native目前只支持内联的样式,不支持我们常用的CSS className继承和复用;第二,React Native采用了类似ReactJS的语法风格,要求有组件封装,在组件A和组件B之间内部互相通信会比较麻烦;第三,对于已有的项目,如果改写成React Native,就会有重构成本。这些问题都促进了ReactMix的诞生。

那么携程要开发ReactMix呢?因为携程90%的代码是历史代码,我们希望能够把这部分代码很平滑的地变成React Native代码。同时,我们希望能够使用H5的特性,提高现有的代码性能,包括渲染性能和执行性能。其实,最主要的原因是节省成本。综合这些原因,我们开发了ReactMix,用来帮助我们很平滑地过渡到React Native,解决一套代码完成H5、Android、iOS通用的问题。据说微软也做了一个插件来支持UWP平台,理论上ReactMix在这个插件下也是可以执行的。所以,可以说ReactMix可以通吃移动端了。

(二).技术文章

1.[译]webpack入门指南

Webpack是目前最火的前端自动化工具,它是一个module bundler并和大部分现代前端相关模块完美结合,包括Babel,ReactJS等等。本文从新手的角度一步一步用webpack配置一个react项目。

2.Learning React Native – React Native 学习线路与过程中遇到的那些坑

分享生产环境中使用 React Native 构建原生应用的学习线路指南,以及相应的技术选型和遇到的坑。

3.React Native学习实践:动画初探之加载动画

该文章很不错的讲解了React Native动画实践,并且实战实现加载进度动画效果,很不错的文章。

4.Promise 与定时器

ECMAScript 6 的 Promise 是一个非常重要的特性,有了它,JavaScript 异步嵌套的问题算是得到了比较好的解决。同时,Promise 也是 ES7 中 async/await 的基础。介绍 Promise 基础的文章已经非常多了,在这里就不再讲解 Promise 本身的用法。本文主要介绍利用 Promise 的特性改良异步 Timer 的一种思路。

5.[译]React Native官方入门教程

翻译官方的RN入门教程,对于初学者会有一个直观的了解。

6.React native fetch获取JSON问题

这篇文章简要的讲解了一下Fetch进行网络请求获取JSON数据,可以参考一下。

7.React Native进阶之原生模块封装基础篇详解-适配iOS开发

封装iOS原生模块给JavaScript进行调用,通过桥接通信。现阶段React Native开发中常用。

8.React Native 进阶之原生混合与数据通信开发详解-适配Android开发

从现阶段RN的发展程度来看,RN和原生混合开发模式是比较理想的,所以我们非常有必要讲解一下RN和原生混合的开发模式,同时里边有关的数据交互通信知识点也有必要讲解一下啦。

9.React 概念模型——脱离React谈谈它的设计思想

在正式学习React之前,我们希望能脱离React本身来了解下React的设计思想,这有助于我们更好地运用React与进行更好地架构设计。当然,这里讨论的一些设计理念肯定还是有争论的,见仁见智,各有所感。React.js本身的学习与实现是偏重于工程解决方案、算法优化、代码兼容以及调试工具这些方法论,不过,这些都是会随着时间以及应用长久的变迁发生改变,唯有设计思想能够绵延流长。

10.我的前端故事—-React算法又是个什么鬼?!

11.前端路由实现与 react-router 源码分析

本文将简要分析并实现一个的前端路由,并对 react-router 进行分析。

12.如何覆盖 React Native 功能测试

本篇介绍如何对 Native 的渲染进行测试,覆盖 React Native 的功能测试等同于覆盖 Native 的测试,需要 iOS, Android 的系统运行时环境。

13.和我一起实战React

本文档还在继续更新,从基础入门开始讲解React,JSX,组件,Props,state,生命周期,动画等等知识点,对我们继续往下学习React Native会打下深厚的基础。

14.react-native 初体验 – 使用 javascript 来写 iOS app

15.ES6 Generator 初体验

听说 ES6 的 Generator 是一个很神奇的函数,所以去了解了一下。 因为它不同于以往的寻常函数,但是带来的体验却非常好 。这里首先讲了 Generator 是什么,分割线后面用了一个例子来说明 Generator 到底好在哪里 ~这篇文章带你了解。

17.React Native开源一周年回顾

官方回顾RN开源一周年中的进展以及后期的发展方向。

18.Going native with React Native-英文版本

(三).开源项目

1.TesterHome 官方 Android 客户端 V1.0.3 版本发布

该为TesterHome论坛的客户端,采用React Native进行开发。

2.React Native开发的猫眼电影客户端

这是一个仿猫眼电影的Android App,基于React Native构建。 由于找到的猫眼API并不完整,所以只能实现部分页面。 代码写得都很简单,欢迎一起交流学习。

3.[译]推荐5个值得学习React Native的开源项目

读源码是最好也是最有效的提升自身编码能力的方式,特别是当该项技术比较新然后它的标准还在不停改进的时候。 ReactNatve 就是其中一个。它的API随着每次发布还在持续的迭代 ,你会碰到很多需要选择的工具然后除了一些简单的HelloWorld教程,稍微深入些的教程比较少。于是,我们还是来读读别人的开源项目源码吧,下面是我follow的5个:

4.基于 React Native 实现的支付宝钱包 UI 界面

该适配iOS平台,作为React Native初学者非常要的页面布局资料哦。

5.侧滑菜单效果开源组件-Android/iOS双平台通用

官方已经封装了Android版本的侧滑菜单组件,但是很多朋友再讲如果实现iOS端呢?OK今天给大家带来了双平台通用的侧滑菜单组件啦。

6.React Native开发的天气预报客户端

经典案例,非常不错,老外使用React Native开发的一款天气预报客户端,牛~

7.React Native开发前后页面翻转效果组件

8.一个演示非常赞的UI组件效果项目

(四).工具

1.2015 – 2016 最新 Sublime Text 主题

Sublime Text 是一款强大的编辑器,它不但拥有众多强大的功能,还拥有很多漂亮的主题。本文为大家分享一些最新的 Sublime Text 主题。

2.一些有趣且好用的 Atom 编辑器插件

3.sublime打造美美哒的开发环境

话说自从楼主开始玩React Native开发的时候,就慢慢开始使用Sublime进行打开了,总体感觉流畅,插件多,清爽,有极客风范,适合装逼 嘎嘎

大写的福利来了~

WebStorm最新版本发布啦,WebStorm做React Native开发还是非常不错的,可惜广大屌丝程序猿没钱啊~怎么办呢?破解吧,嘎嘎

既然说是福利,那么福利来了,破解传送门:http://idea.qinxi1992.cn 选择webStorm的注册码,点击第二项,license server

感谢田小新丶童鞋推荐

尊重原创,未经授权不得转载:From Sky丶清(http://www.lcode.org/) 侵权必究!

关注我的订阅号(codedev123),每天分享移动开发技术(Android/IOS),项目管理以及博客文章!(欢迎关注,第一时间推送精彩文章)


Pepperoni is a blueprint for building cross-platform mobile experiences rapidly with ready-to-use integrated building blocks for common mobile app features.

$
0
0

WHAT IS PEPPERONI?

A delicious blueprint for mobile development


Pepperoni is a blueprint for building cross-platform mobile experiences rapidly with ready-to-use integrated building blocks for common mobile app features.

The Pepperoni blueprint is crafted on a solid foundation using modern architecture and industry best practices, featuring:

  • Native mobile apps built with React Native by Facebook and Redux
  • Mobile backend powered by NodeJS and PostgreSQL (coming soon)
  • Cloud-ready for Heroku, Amazon Web Services, Google Cloud Platform, Microsoft Azure, and others – or host it yourself!

React Native开发技术周报Issue#12

$
0
0

React Native开发技术周报Issue#12-技术干货More More More

尊重版权,未经授权不得转载出处:http://www.lcode.org

本周报来自江清清的技术专栏,欢迎微信关注公共号:codedev123.精彩技术文章第一时间推送!

说在前面的话:React Native开发技术周报,主要会涉及React Native最新资讯,React Native教程,技术开发文章,开源项目,工具,视频等等。今天是我们的第十二期,同时各位朋友有优秀的有关React Native技术开发文章可以发给我。

React Native交流6群:426762904

(一).资讯

1.Deco:The best IDE for building React Native apps is now free and open source.

React Native IDE终于发布了,不过当前支持Mac端iOS开发哦,Linux以及Windows版本不知道什么发布哦,工具虽然可以加快开发效率,不过当前Deco还是有一些细节问题优化的。http://pan.baidu.com/s/1bpNrzFT 密码: qnb9

2.旅行喵 React Native 技术实践

 炳根大神的又一大招放出来了~

3.React-Native痛点解析之开发环境搭建及扩展

好吧下面来一波Realm React Native应用详解专题~

4.移动端数据库新王者-Realm React Native版本应用详解之抛砖引玉入坑篇(一)

5.移动端数据库新王者-Realm React Native版本应用详解之略陈固陋爬坡篇(二)

6.移动端数据库新王者-Realm React Native版本应用详解之略陈固陋爬坡篇续1(三)

(二).技术文章

1.React Native进阶之原生模块封装特性篇详解-适配iOS开发

该文章主要讲解原生模块的一些特性例如:回调方法函数,Promises,多线程,常量设置,事件发送到JavaScript,监听生命周期事件,获取封装Swift原生模块等相关的特性。

2.React Native系列文章(七)原生模块(上)

ReactNative目前更多的是用于在原生App中加入一个新的模块。那么,此时如果这个ReactNative模块需要使用到一些原生模块的功能,比如访问平台的API;或者你要复用现成的Java代码;又或者使用Java已经成熟的第三方Library,那么这篇文章会一步步告诉你,如何去调用一个已经封装好的Android原生代码。

3.React Native系列文章(七)原生模块(下)

上一篇文章React Native系列文章(七)原生模块(上)中我们介绍了原生模块的基本用法,本篇文章将介绍原生模块的高级用法—ReactNative与原生模块的通信方式。

4.React Native 热加载(Hot Reload)原理简介-中文版本

官方博客,热加载原理介绍,下面一片是原文,喜欢都英文的大家可以读一下哈

5.Introducing Hot Reloading

官方热加载原文版本

6.用 React 整合 LogEntries JavaScript 库

众所周知,React.js已经被证实是众多JavaScript架构中的有力竞争者。按理说,它已经成为web开发人员应当考虑的,在当前及未来项目中使用的少数项目库之一。而了解它如何与技术栈中的其他库相集成,是非常重要的一环。如果你目前正在使用LogEntries,或者考虑使用LogEntries,那懂得如何集成React.js和LogEntries就非常关键。本文将阐明他们间的互操作性。

7.实例讲解基于 react+redux 的前端开发流程

在当下的前端界,react 和 redux 发展得如火如荼,react 在 github 的 star 数达 42000 +,超过了 jquery 的 39000+,也即将超过前几年比较火的angular 1 的 49000+;redux 的 star 数也要接近 20000,可见大家对其的热情程度,究竟是什么魔力让大家为之疯狂呢?让我们上车,亲自体验一波试试~~本文章偏向于讲解redux流程。宅印前端基于 react + redux 的模式开发,我们指定了一套分工明确的并行开发流程。下面通过一个 “苹果篮子” 实例,来看看整个应用开发流程。

8.ES6的变量声明

在ES5中,变量声明只有var和function以及隐式声明三种,在ES6中则增加了let,const,import和class四种,以下来介绍着七种变量的声明。

9.JavaScript函数式编程探索与思考

函数式编程是一种编程范式,它将电脑运算视为数学上的函数计算,并且避免使用程序状态以及可变数据。函数式编程强调程序执行的结果而非执行的过程,倡导利用若干简单的执行单元让计算结果不断渐进,逐层推导复杂的运算,而不是设计一个复杂的执行过程。今天我试图用js去梳理函数式编程相关的一些知识。文中代码风格采用Standard,使用ES6语法。

10.深入浅出 React Native:使用 JavaScript 构建原生应用

11.react native debugger 远程调试redux工具

react native是现在比较火的App开发技术。使用react native开发的朋友一般也会使用到facebook提出的Flux概念框架,而redux框架是使用的比较多的。redux的一大原则是单一数据源,只存在唯一的state树,以前由于工具的缺失,react native查看不了state,刚使用redux的时候按照文档安装了chrome扩展,也查看不了state树,每次都要自己打印出来看,比较麻烦。想来都说的是web的工具,今天找到了react-native的工具,可以远程调试redux。

12.我们如何使用React Native和Parse开发Out the Window

本文是介绍工程师如果使用React Native和Parse技术进行开发Out the Window应用的

13.重写SHOULDCOMPONENTUPDATE指定组件是否进行重绘

14.统一ANDROID与IOS两个平台的程序入口&&区分平台的组件简介

15.Pepperoni是React Native的入门起步套件

Pepperoni是使用React Native开发针对安卓和iOS的入门套件工具,使用这套起步项目模板,你就节省了繁琐的项目准备设置,也不要每个项目重复进行设置。它包含了React Native生态系统的很多工具。是一个应用模板Blueprint蓝图。

16.安卓转战React-Native之windows下android环境搭建爬坑血泪史

17.无需Webpack开撸React

Webpack虽好,但对于一个React新手来讲,如何开始是个很大的挑战。我就遇到很多初试身手的开发者在学习React的康庄大道上被难倒而功亏一篑,原因就是陷入了Webpack和配置的坑里。为证明你可以专注学习React而无需ES2015、JSX编译以及Webpack的帮助,我撸了一个样例库,你可以在GitHub得到它。这个仓库使用Gulp来合并、压缩你的文件,无需ES2015或是JSX。要是你想专注于React,余事勿扰,那就不妨一试。

18.实例讲解基于 React+Redux 的前端开发流程

19.fetch简介: 新一代Ajax API

AJAX半遮半掩的底层API是饱受诟病的一件事情. XMLHttpRequest 并不是专为Ajax而设计的. 虽然各种框架对XHR 的封装已经足够好用, 但我们可以做得更好。更好用的API是 fetch 。下面简单介绍 window.fetch 方法, 在最新版的 Firefox 和 Chrome 中已经提供支持。

20.React Native Module for CodePush 入门

21.React Native Module for CodePush 实战

22.ReactNative中组件调用源码分析

本文主要在源码上分析了Java组件如何最终能够调用JSX的方法细节。首先上结论,RN完全没有使用HTML/WebView,而是通过基于C的javascript解释器(or VM)与native代码相互调用的.

23.[深入ReactNative]第一篇 通讯及消息循环代码剖析

本篇详细分析React Native 中 Native和JS的互相调用的原理解析。

24.React-Native-APP-With-Testing

本文章介绍在开发react-native app的过程中如何去组建一套比较容易理解和使用的测试框架进行UT和component UT,这里做一下整理。

25.React-Native之flexbox布局篇

这篇博客稍微讲解下React-Native中的布局。比较简单。RN的而布局是用css中的flexbox布局,所以布局起来与Android传统的布局样式有点像。接下来赶紧去学习吧,作为React Native的开发基础非常有必要哦

26. React Native之底层源码分析篇

今天就从源码的角度来分析下React-Native底层的通信机制。了解下底层是如何通信的对开发也有所好处。

27.React-Native系列Android——Javascript文件加载过程分析

React-Native应用程序的内容是由JavaScript语言开发的,而Android或者iOS手机系统只是一个容器和各类服务提供者。众所周知,Javascript是一门解释型脚本语言,对于浏览器而言,浏览器负责解释和执行Javascript脚本。而对于手机系统而言,同样是负责解释和执行Javascript脚本,当然其核心都是使用的webkit内核。

浏览器获取Javascript脚本,主要通过网络下载 + 本地缓存的机制,达到效率的最大化。当然,移动应用也不例外,但不同的是移动应用可以将Javascript脚本直接打包在应用程序内,免去网络下载这个极其不稳定的过程,这样可以达到加载效率和性能流畅的最大化,也就是风靡一时Hybrid技术,而这一点浏览器是做不到的。无论使用网络下载还是本地文件,最终都是要加载JS文件,而React-Native项目中包含大量的JS文件构成的框架和组件,那么Android框架又是如何去加载它们的呢?这个过程就是本篇博客的研究的主题了!

28.React Native中 Back 键的攻坚实战

本文作者从实际项目总结Back键的最佳实践

(三).开源项目

1. 底部tab:https://github.com/exponentjs/react-native-tab-navigator

2. 轮播图:https://github.com/sincethere/react-native-banner

https://github.com/leecade/react-native-swiper

3. Fetch:https://github.com/sincethere/easier-react-native/blob/master/http/FetchUtil.js

4. 本地持久存储:https://github.com/sunnylqm/react-native-storage

5. View Page:https://github.com/skv-headless/react-native-scrollable-tab-view

6. 选择星星:https://github.com/bluesky0109/react-native-starRating

7. toast:https://github.com/magicismight/react-native-root-toast

8. 加载中:https://github.com/mohebifar/react-native-loader

9. 国际化:https://github.com/joshswan/react-native-globalize

10. 选择列表:https://js.coach/react-native/react-native-actionsheet

11. 圆性加载进度条:https://js.coach/react-native/react-native-circular-progress

https://github.com/oblador/react-native-progress

https://github.com/jeanregisser/react-native-slider

12. Date picker:https://js.coach/react-native/react-native-picker

13. 背景虚化:https://github.com/magus/react-native-fxblurview

14. 懒加载:https://js.coach/react-native/react-native-lazyload?page=3

15. 字母检索列表:https://github.com/xcarpentier/react-native-country-picker-modal

16. 图片选择:https://github.com/marcshilling/react-native-image-picker

17.React Native开源封装AES,MD5加密模块(react-native-encryption-library)

封装了常用的加密方式例如:MD5,AES加密,供React Native进行使用,同时适配Android和iOS平台

18.React Native plugin for Universal Windows Platform(UWP)

UMP的React Native插件

19.React Native平台Material设计效果弹框(Android平台)

(四).工具

1.淘宝 NPM 镜像

作为在墙内的童鞋们,进行安装npm的时候经常因为网络问题加载不成功,这边提供国内淘宝镜像,助大家一臂之力,速度非常的快哦~

2.react-native-babel(使用ES6+)

3.gulp-react-native-css(就像写css一样写React Style)

尊重原创,未经授权不得转载:From Sky丶清(http://www.lcode.org/) 侵权必究!

关注我的订阅号(codedev123),每天分享移动开发技术(Android/IOS),项目管理以及博客文章!(欢迎关注,第一时间推送精彩文章)



为了告别革命 |陈坡:共产主义探源

$
0
0

为了告别革命 | 陈坡:共产主义探源

暴力革命曾被马克思赋予神奇的力量可将最被异化的粗鄙的无产阶级改造为共产主义的新人,而于革命内战中历练的“革命者种族”却是“持久地、残忍地失去清白”,列宁的战时共产主义是俄罗斯历史上最悲惨的世界……

他们“从那一特定历史时刻诞生之日起,就培育了整个他们自己的种族,这一特殊的种族将在文明世界的各个领域里迅速地繁衍、壮大。无论在哪里,他们将保持着同样的面貌和同样的特性。我们知道这一种族的萌芽状态,而至今,它仍旧活跃在我们的眼前”。

革命,真的可以告別吗?

——引自本文第97、99节

共产主义探源

作者:陈坡,党史专家,1982届北京大学中共党史研究生,法学硕士。现任北京大学历史文化资源研究所副所长。参与主编《文化大革命辞典》、《共和国重大决策内幕》(四卷八册》、《告別乌托邦》(上、下)。作者今年在互联网上发表的《文化大革命沉思录》、《文革前史刍议》、《现代史识》等长文引发好评和讨论,成为文革发动五十周年这个特殊时间段中重要话题。

二十世纪以列宁为标记的共产主义曾经是深刻影响了人类命运的世界体系的一极。苏联共产党最后一任总书记戈尔巴乔夫在其回忆录里称他的政治改革思想基于正宗的列宁主义一一一切权力归苏维埃,由此导致的普遍自由的全民选举最终丧送了列宁缔造的苏联与苏维埃。毛泽东手中的一把刀子成了戈氏的民主利器,真是“情人眼里出西施”。翻阅费正清主编的《剑桥中华人民共和国史(1966-1982)》,赫然在目的章节有“共产主义统治下的农村”、“共产主义统治下的生活与文学”,科尔奈的名著《社会主义体制》的副标题是:共产主义政治经济学。在美国人看来,文化大革命的中国就是共产主义的实验、运动与社会国家。布热律斯基称邓小平改革中的中国是“商业共产主义”。美国人对当代共产主义的识別从来未曾认错,列宁式共产党专政的土地,才有共产主义。那么,共产主义的祖师是谁呢?列宁、马克思、魏特林?还是布朗基、邦纳罗蒂、巴贝夫?以至有人追溯到伟大的基督?

即使对列宁主义,也是人言言殊。且不说列宁的同时代人考茨基在《恐怖主义与共产主义》中批评“从废除一切形式的出版自由开始到实行大批处死的方法为止的恐怖主义”,是“共产主义方法的必然的结果”,二十世纪六十年代的西班牙共产党理论家克劳丁在毛泽东高呼“列宁主义万岁”的时候,就尖锐地指出:“列宁一逝世,’马克思列宁主义’的正统思想很快蜕化成了马克思主义历史上没有先例的教条主义,成了一种异己思想,代表了斯大林的工业化过程中产生的新的统治阶级的利益,并为这种利益服务”。另一位与恩格斯相识的德国社会民主党人比尔则称:“一个民族必须达到多么高的政治和精神文明水平,然后才能从事整个社会的社会主义改造”。而青年马克思把野蛮状态下的共产主义称之为粗陋的“普遍奴役制”。

共产主义的思想与运动起源于法国大革命的后期,巴贝夫学说是其典型的表现。刚近而立之年的马克思与更年青的恩格斯以共产主义宗师的自信向全世界发布《共产主义宣言》时,曾对此前各种社会主义共产主义学说冠之以“封建的”、“小资产阶级的”、“德国的或真正的”、“保守的或资产阶级的”、“批判的空想的”予以横扫式批判,只是字里行间偶尔对其创始人有所敬意,其追随者则“总是组成一些反动的宗派”,但对法国大革命恐怖时期的巴贝夫的“平等派密谋”无一字批评,这是意味深长的,因为这是把共产主义变为现实的首次尝试。法国大革命是现代共产主义的摇蓝。虽然共产主义是近世的产物,作为一种否弃私有财产与追求共同生活并强烈地向往返朴归真回到初民社会的共产主义情绪与思潮,却源远流长,较鲜明地体现于罗马后期的犹太教与基督教的信仰与信众及那时代的诗人思想家。

宗教与共产主义思潮往往活跃于文明的衰世,其时由财产分化与社会分化而创造的文明所导致的社会问题与道德问题也比较突出,人心返古。《死海古卷》有公元前二世纪以后犹太教艾赛尼派远离世俗创建公社式社会即库兰宗团的材料,古犹太史家约瑟福斯载库兰宗团“实行凡物公用,使得富裕的人与一无所有的人享用相同。这样共同生活的人约有4000,他们都不娶妻,也不用奴隶……生活在一起,彼此服务,互相帮助。他们还指派若干执事负责经管他们的收入和土地的出产”。《死海古卷》有文件记载了加入宗团的义务,如要使自己不染指不义之财,不要染指圣所的财产,要按照规定细则缴纳各项应交的费用,要爱邻居如同自己……斐罗也报导库兰宗团只有圣库,无私产,共用衣橱,共同在公共食堂吃饭,个人所得全部上缴公库。《会规》有财产公有制的条例。《死海古卷》的发现证实了公元前二百年间巴勒斯坦西部犹太人的宗教共产主义生活、社会与信仰。

对于人类而言,部落意识比文明意识更古老更根深蒂固,因为人类在部落群体中演化了几十万年甚至上百万年,而文明则至多只有七千年的历史。农作物的栽培,动物的驯养与青铜生铁运用于工具制造,才使人类有了剩余财富、分工与交换并把人类推入文明的创造,文明是极其脆弱的。文明之火在大地上的燃烧也是屡灭屡旺,而当文明陷入危机,人们本能地幻梦最初的乐园,如婴儿之恋母怀,是极其自然的。一千余年间,蒙古草原悍猛的铁蹄随时可以踏碎农夫的家园与城市帝国,阿提拉,成吉思汗,曾在漫长时期是农业种群的恶梦。罗马时代的大诗人称颂远古的农神之世:“没有篱笆和界石一一 來分开田垄,没有土地的争讼,天下为公”。贺拉斯对西徐亚人的赞歌:“平原上的西徐亚人,愉快地住在漫游的車子里。幸福的胖子格坦,耕种着共同享有的土地”,也是一种返古返祖的咏叹调。小国寡民……甘其食,美其服,安其居,乐其俗。邻国相望,鸡犬之声相闻,民至老死不相往来。

对远古部落社会纯朴美德的理想化在各大民族的集体意识中都有表现,如中国春秋时《礼记》描述的大同世纪,孔夫子礼赞的尧舜之世,古希腊赫希奥德的黄金之世,《圣经》的伊甸乐园,而最生动描述原始共产主义的,是古罗马后期的世界哲学家塞涅卡,他写道:“在贪欲还没有打乱社会而带来贫困之前,社会的美德依旧保留着纯洁无瑕的面目,因为人类一旦把任何一件东西称为自己的所有物时,便不能共同拥有全部的东西了。原始的人类和他们的后裔都是真朴、纯结而无邪的。但是自从罪恶偷偷侵入之后,帝王便不得不行权力制定刑法了。在原始时代,大自然赐给的一切都是归公众所有,人们可以一律平等共同享用,也没有贪念和奢侈来分裂他们,使他们互相残杀,那时是多么快乐啊!他们共同享受自然的一切,因而能够安然占有公共财富”。上德不德,是以有德。下德不失德,是以无德……故失道而后德,失德而后仁,失仁而后义,失义而后礼。夫礼者,忠信之薄而乱之首。

原始基督徒的共产主义生活与情感是无可置疑的。使徒行传中载使徒把一切都归为公有。西比连称:“教会初成立时,信徒的心灵被新的信仰火焰燃烧着,思想里充满了伟大的美德,那时一切东西都归公有,他们仿效神法,仿效天父上帝的公平原则”。共产主义的核心意义是民主公有制。但这类共产主义理想的实现途径是严格地恪守宽恕克己的伦理法则,如耶稣那样以一己的从容牺牲为人类赎罪。保罗创立的普世救赎是以耶稣被钉十字架为标志而将人类世界划分了旧时代与新时代,末日审判就是新时代的开端。《福音书》是为末日审判做准备的创作。旧时代是以偶像崇拜的精神奴役为特征的,耶稣基督的启示使人类进入一个自由时代。天启末世论是一场人类的解放战争。那些选择严守律法的人类将在最后审判中获救。克雷孟一世演讲说:“正如空气无法分配一样,阳光亦是如此,尘世间赋予我们以使其共有的其他财产也再不应受到分配,而是确实应该受到共同的管理”。马克思亦认为共产主义是一场犹太教派以及第一批基督教修道院的运动。欧洲中古前期的基督教社会对私有财产的控制是这种宗教精神的兴盛时代。

如果说共产主义思潮因原始基督教而流行于世,那么,必须强调,这种返朴归真的愿景是以耶稣和平博爱的伟大精神为前提的,暴力、专权与政治奴役与此绝不相容。中世纪关于共产主义的讨论,是由神学思想家开展的。圣方济各会与圣多明我会是有力的推动者。欧洲中古时代百科全书式的神学家托马斯-阿奎那把共产主义划入理想境域,而承认纯朴状态已经消失,对穷人应施与救济,阿奎那称:“如果不是别人太少,一个人断不能有所多余”。托奎那的师长黑耳斯则称在自然状态下共产主义是公平、公正和良好的,而在腐化的自然状态下私有财产才是好的。也就是说,人性变坏以后,世俗政府便不得不保障私有财产了。格拉济亚努斯的《教令集》将公有财产视为准则。奥卡姆则指出,私有财产与政府权力,只有在有利于被统治者并获得被统治者的同意才是合理合法的。基督和他的使徒是绝无私产的,基督的志向远远高于共产主义。

十三、十四世纪是欧洲中古世界开始衰落与城市商业社会兴起的转折时代。对农村公社土地的侵蚀引起了英国和其它地区广泛的共产主义骚乱。奥卡姆的门徒威克里夫倡议用王权来保护农民公社,但其学说坚决排除以任何煽惑、叛乱、暴力和党争实现共产主义。他的弟子宣道师约翰-波尔在传道词中就号召拿起武器除恶扬善,“只要我们大家都联合起来……财产才会全被公有,既无农民、又无老爷的时候才会出现”。波尔的政治与革命鼓动使共产主义超出了中古神学的学术讨论。路德的宗教改革改变了德意志,改变了欧洲,也改变了世界,其实际影响大大超过了文艺复兴。路德的门徒闵采尔号召为实现消灭私有制消灭国家的无政府共产主义发动圣战,以在尘世间实现无约束的兄弟之爱,称“今日的被拣选者必将踩着《圣经》中杀人犯的足迹前行。”共产主义的暴力面目初露峥嵘。

闵采尔是一位渊博的古典学者,也是再浸礼教派中神权政治的第一位领袖。他称基督进入他的灵魂,因而有了一双洞察神的意志的慧眼,负有神的使命。他认为不应在來世而应在现实生活中寻找天国,信教者的使命就是在地球上建立天国,以迎接基督的回归。他把图林根州一个镇上的矿工组织成“被选择者联盟”。这些穷苦大众将要建立一种强制的、平等派的共产主义的统治,将世上所有财产共同所有,人人平等,各取所需。闵采尔又到米尔豪森高擎十字架参加自发的起义,呼吁“应该把权力交给普通人民!”成为农民运动的领袖。他与其同志在1525年接管了米尔豪森市并颁布法令把财产沒收为公有,强占修道院,创办了共产主义公社,以至人们无所事事抢劫谋生。“托马斯[闵采尔]使这种抢劫成为制度化的行为,并且日甚一日”。他在鼓动农民反抗王室镇压的宣讲时,虽然天边突然出现了象征的彩虹,起义者仍被打败,闵采尔被处死。“万物公有”,是闵采尔的供词,也是遗言。闵采尔的追随者订书匠胡特又意图在惠特森蒂德建立共产主义千禧年王国,被地方当局投入监狱。闵采尔为恩格斯评价为共产主义的先驱。

十一

在十六世纪三十年代奋起反抗压迫的德国农民暴动所波及的西北部地区,有一个万人首府城市明斯特。再浸礼教派的牧师罗施曼宣称共产主义运动早已存在于共同享用财物的原始基督教教会中。他宣称所有的弥赛亚预言都会以完满的爱君临世界的明斯特变成现实。在他的呼唤下,大批流浪汉负债人涌进明斯特。闵采尔的后继者荷兰面包师马蒂斯在皈依者裁缝博克尔松及大批再浸礼教徒占领了明斯特并对全城进行了三天大规模抢劫后,成为明斯特名副其实的独裁者,发起了一次史无前例的共产主义实验。首先是清除那些不洁净不信上帝的人,将天主教徒与路德教徒赶出城市,包括老残妇孺,没收被驱逐人的财产,留住城市的只能是“上帝之子”,建立中心仓库,穷人按需分得物品,对异议者残酷镇压。马蒂斯宣布取消货币,工资以实物发放。沒收所有私人住房,建立了公共大食堂。1534年3月马蒂斯宣布除《圣经》以外所有书籍非法。于是将公共和私人藏书全部焚毀。全城信众只能听从马蒂斯及再浸礼教对圣典的解释以打造新人。與论一律。

十二

狂热的马蒂斯被围城的主教部队打死后,明斯特被自称为“更为强有力的先知”博克尔松所控制。他声称是大卫的继承人,通过在大街上裸奔吸引市民的关注并组织了十二名长老的统治委员会为辅助,独揽权力,主掌明斯特居民的生杀予夺,并以强迫劳动驱使居民为公社国家的雇工,对任何反抗行为判处死刑。博克尔松还决定在明斯特强制实行一夫多妻制,他自己娶了十五个妻子。长老们还规定一定年龄以下妇女必须结婚。不少拒不执行的女子被处死了。清教主义的社会瞬间变为滥交的公共娼所。1514年8月,博克尔松宣布自己是“新圣殿之王”、世界之王和末日救世主,声称有“支配地球上所有民族的权力”。他对有怨言的公众说:“就算你们所有人都会联合起来抵制我,我仍将君临天下,对你们不管不顾,不仅统治这城,还当统治全世界,因为天父心愿如此,而且我现在开始的统治将永不衰落地持续下去”。

十三

博克尔松在公共广场的金色王座上登基称王,其王家侍从都被封为高官。他的正夫人迪瓦拉被宣布为世界的王后。国王有200多人的豪华卫队拥挤在一所豪奢公馆内。明斯克所有的马匹被征用以组建国王的骑兵中队。博克尔松剥夺民众的剩余产品与其奉承者花天酒地,而居民在严格限额下过着饥饿的生活。博克尔松向居民保证将征服全世界,耶稣将降临,人人享有奢侈生活的平等的共产主义必将实现。1535年1月明斯克被王公与主教的军队围困,城里为饥荒笼罩,博克尔松保证上帝将变鹅卵石为面包,命令饥饿的民众开展连续三日的舞蹈与体育活动,以满足其对剧场的嗜好,对非议国王者一律立即斩首并由博克尔松亲自操刀。1535年6月24月被围困一年零三个月的明斯克被攻陷,几百名再浸礼教信徒在投降后惨遭杀戮。博克尔松被拴着铁链游街示众并被公开拷打致死,其尸首放进一个铁笼中悬在一个市场教堂的塔楼上。而今囚笼犹在,尸已不存。波尔布特的柬埔寨是明斯特共产主义实验的二十世纪版本。

十四

从十二世纪意大利修道院院长约阿基姆提出三段式修道院共产主义,到闵采尔的思想导师一一十四世纪极端塔波尔派的德意志神秘主义,都以千禧年末日审判为预设的目标,指明上帝在末日审判前要在地球上建立一个神圣纯洁的教会,为了重归昔日的黄金时代。极端塔波尔派提出要返回捷克早期无阶级无私有财产的状态,通过革命暴力在波希米亚创立共产主义上帝王国并将这种共产主义强加给全世界。其布道者称“所有的东西都是公共的,包括妻子。这里都是上帝的自由的儿女,他们将不会结婚,形成由丈夫和妻子两个人组成的联盟”。他们要帮助上帝加速实现这一目标。塔波尔派及其后继者波希亚亚当派都依据其教义进行过共产共妻的实验,也都失败了。法国学者内莫说:“在教皇革命的谱系中,某些人会追随世界渐进改善的理想,运用理性和法律的工具,使心灵深处的皈依、个体的努力和责任成为达成理想的动因。另一些人则按照前理性的和祭献的思想,否弃个人责任,倾向于为恶寻找’替罪羊’,意图自现在起就使千禧年来临,这样必将付出使世界血流成河的代价。”

十五

与德国农民暴动领袖闵采尔践行的千禧年共产主义之同时,是英国的另一个托马斯-莫尔,他构想了一个共产主义乌托邦。其时代背景是羊吃人的圈地制度,贵族领主把公共草地圈为私人所有,驱赶农民,如莫尔所言:“绵羊过去是那么地温顺,吃的是那么少,现在则变得贪婪、野蛮,竟把人本身也吞噬了……因为它们没有留下一块可供耕种的田地”,圈地制度侵蚀了中古的农村公社,加速了社会的贫富分化。所以,莫尔批评所谓国家都是富人保护本身利益的阴谋组织,“他们口称为了国家的利益,其实是为了他们自己的利益”,金钱与虚荣是罪恶之源,世上一切罪恶都来自贪财,贪婪将毀灭英国,共产主义比私有财产更有益于美德。莫尔的另一个灵感的来源是航海家对美洲的报导,如“当地的人民过着原始生活……他们没有私产,一切东西都归公有。他们没有帝王,没有统治权,每个人都是自己的主人”。莫尔认为自然状态就是纯朴无邪状态。莫尔1516发表的《乌托邦》把共产主义当做一个社会改革问题,宣示另一种可能的愿景与前景。

十六

《乌托邦》是以对话体撰作的一本小册子,刊行以后流传为一部不朽的文学经典,这与莫尔的人文素养有关。《乌托邦》有两部分,第一部分是对时弊的批评,第二部分是对一个典范的共产主义共和国的叙述。莫尔的乌托邦是以农业为基础的财物公有的共和国,由选举产生的议会加以管理,对社会经济与活动实行高度集中的计划,要求每个成年人每天必须劳动六小时,晚八时入眠,晨四时起床,吃公共食堂,严格实行一夫一妻制,实行宗教信仰自由,对不宽容的基督徒予以逐出。莫尔评论:“乌托邦中有许多东西是我在英国只能想望而不能期待的”。莫尔对国王及王室大臣没有信心,他借书中人物抨击国王只想战争、征服与扩张权力,而大臣们只知逢迎、称颂、助纣为虐并对民众课以重税。所以,必须彻底改变私产至上的整个社会制度。莫尔也怀疑共产主义消除了个人利益的激励动机,可能导致懒散怠工因而产生普遍的贫困,又会因贫困而引起争权夺利的斗争。乌托邦岛的样板就是英格兰。

十七

十六世纪前三十年在欧陆与英国发生的普遍的农民骚乱与千禧年共产主义运动是中古世界衰落所引发的深刻不安,农村公社的农民是不安的主体。莎士比亚借戏中的人物表达了这种捍卫公社权利的愿望:“我已经想过了,必须这样。走吧,把这儿的文卷都烧掉,我的口就是英格兰议会……今后一切都将共有”。虽然德国的明斯特共产主义曾被马克思主义理论家考茨基颂为“在共产主义青春光芒四射的时刻壮烈牺牲”,其恐怖统治却震惊了欧洲大陆,引起对共产主义幽灵的广泛警觉。莫尔的《乌托邦》,既有人文主义与自然神论的温和理性,又具方济各会属灵会修道院式理想国的要素。作为皇家大法官与伦敦公民的莫尔对失地农夫的悲悯情怀是感人至深的。其临刑前之陈词是:“愿做国王的忠仆,但要先效忠上帝”,他也因《乌托邦》而在共产主义思想史上留名千古。据载,莫尔被处死刑后的14年一一1549年一一英格兰半数农民都卷入了保卫土地的叛乱。

十八

英国伊丽莎白女王时代的济贫法改革及其他社会改革把中古共产主义推到幕后了,商业文明与个人主义在中古农村公社的土地上不可遏止地成长起来,开启了科学与实验的世纪,随着日不落帝国在全球范围内奠基,工业化时代的烟雾吞没了广阔的乡村。斯宾塞在“仙后”中描述共产主义巨人要用大秤平衡人间,引得“下流之徒人头钻动,围在四周听他的谬论,好象愚蠢的苍蝇看着糖罐,嗡嗡嗡嗡围着直转,希望通过他获得大量外快,毫无拘束自由自在”,虽然这个巨人豪言要“把富人的全部财富转归贫民所有”,还是被击败并投入汪洋大海,原想通过共产主义革命得到许多好处的流民希望幻灭,乌托邦变成了“逗人开心的笑谈”。而欧陆爆发的法国大革命,又把幕后的共产主义推向前台,这就是现代共产主义的真正起源一一巴贝夫“为平等而密谋”。

十九

1796年法国大革命后期的巴贝夫密谋对现代历史之影响不在当时,而在后世。被后來当做“革命者手册”广为传播的《为平等而密谋》,是幸免于死的巴贝夫战友邦纳罗蒂所作,其书详实地记述了巴贝夫密谋的全过程,尤其是密谋案件的审判细节,为断头而死的巴贝夫立传并使他成为现代共产主义的先驱。巴贝夫的《平等派宣言》实质上是一篇共产主义的政治声明。巴贝夫宣布私有财产是一切社会灾难的根源。土地与工业收归公有和财产均产才是国家的真正目标,为此目标可采用前所未有的恐怖手段。在雅各宾恐怖领袖被清除后,曾六次入狱的巴贝夫计划以其地下组织万神会为骨干并联合雅各宾派地下残余分子在巴黎夺取政权,建立以巴黎城市贫民与工人为主体的临时专政,立即没收财产,废除继承权,实行配给制,如《平等派宣言》称“大自然赋予每个人以平等享用财货的权利”,未来只有把财产捐献给公社的人才有公民资格,其余的人一律被排除为外国人,有嫌疑即可逮捕。所以,巴贝夫密谋明确地展开了穷人反对富人、无产者反对有产者的公开政治斗争并发现了革命专政的工具。

二十

巴贝夫是在法国革命过程中将社会问题提到生死存亡程度的最彻底的革命煽动家,在《平等派宣言》中称:“从现在起,在全法国要消灭私有财产拥有者”,他提出“财产和劳动的共有制”,其实施措施是“建立公共管理局,取消个人财产,人尽其才,各施所能,将劳动成果存放公仓,建立一个简单的给养分配管理局,由它对所有人的物品作翔实登记,并对物资进行最公平的分配”。巴贝夫在1796年3月秘密成立了起义委员会,核心是一个领导小组,试图策动巴黎武装部队一一治安军团兵变,一份“起义法令”已被草拟印发,箭发之时,被巴贝夫的军事联络员告发密谋,巴贝夫等128人先后被捕。他被装进铁笼车押送到旺多姆,接受审判。密谋失败。临刑前,巴贝夫写道:“我只是为了人民的正义与幸福活到了今天!”巴贝夫密谋仅仅是法国大革命终结时的一道闪电,却成为引发以后一系列暴力革命的狂风骤雨的诱媒。索布尔指出,巴贝夫领导的“平等派密谋”是以暴力摧毁现存社会结构使共产主义变为现实的第一次尝试,超过了空想的阶段,他紧密依靠少数忠诚的历经考验的革命积极分子,形成了革命专政的意识,对于创立新政权以推行共产主义改造社会来说,维持极少数革命者的专政是必要的。这一理念通过邦纳罗蒂传授给布朗基,后者又启发了列宁。

二十一

巴贝夫行动在共产主义发展史上的重要性是把共产主义思想首次变成了一种政治力量。他曾宣称:“法国大革命究竟是什么?是一场贵族和平民、富人和穷人之间的公开战争”。他在囚禁中嘱把他“关于民主和革命的全部计划、笔记和草稿”保存下来,以便把“称为我的幻想的东西介绍给全体追求平等的人”。巴贝夫的革命传人布朗基是不断密谋不断起义又不断坐牢的职业革命家,他自称是“共产主义者”,他认为共产主义并不是乌托邦,其本身就是革命,永远不能与政治分开,政治不过是共产主义的服务员,军队,学校,监狱,兵营,都是共产主义的萌芽。“社会发展的全过程都包含着共产主义性质的革新,共产主义不过是最终的協作方式而已”。共产主义应分阶段实施,必须有一个具有高度纪律的少数职业革命家的专政时期以对民众进行教育。这个觉悟的少数通过暴动夺取政权,建立专政。布朗基从十九世纪三十年代起不断策动的革命到巴黎公社达到高潮。马克思称其为“无产阶级政党的真正领袖”。

二十二

巴贝夫与布朗基的共产主义已经脱离宗教的原生态。末日审判的恐怖图景已被未来社会的美丽新世界所取代。法国大革命反宗教的狂暴造就了一代又一代无神论者,传承着十八世纪法国霍尔巴赫拉梅特里为代表的“人是机器”的粗俗唯物主义,其与德意志中古神秘主义的结合还将主宰半个地球的一个世纪。巴贝夫在手撰的《耶稣-基督新史》中写道:“我毫无容情地攻击我们哲学家们所敬畏的这个主要偶像,迄今为止,他们只敢对他的随以、伴侣进行攻击……基督既不是无套裤汉,又不是真诚的雅各宾党人,既不是明哲之士,又不是理性论者,既不是哲学家,又不是立法者”。而在监牢中度过近半生的布朗基,则是一个“不断地斗争,不顾一切地斗争,一直斗争到死”的职业革命家的典范。他的名言是:合法的权力属于坚持抵抗的人,今天的选票就是子弹。

二十三

法国的卡贝是莫尔《乌托邦》共产主义设想在十九世纪中叶最具影响的代表。他发表的《伊加利亚旅行记》设计了一个功能齐全的共产主义社会,其中人类的一切活动都由国家安排,财产公有,计划经济,公共仓库,各取所需,家庭组织为社会的基础。但曾是烧炭党人的卡贝后来认为新社会决不能凭借暴力而要在说服与辩论中和平诞生。他和他的信徒在美国的伊利诺斯州的诺沃地区创办了一个乌托邦移民区一一“伊加利亚”。当然在实际建设中对卡贝的公社集体制有所变通,如容许个人保留财产,人数也不是原来构想的一百万而是一千五百人,却坚持下来了,后来的“新伊加利亚”一直实验到1895年。卡贝信仰上帝,其著《真正的基督教》主张以基督为榜样,复活原始教会时期基督徒的“共产主义”。卡贝的实验也证明空想社会主义并不空想。

二十四

可以说,现代意识形态起源于法国大革命,虽然从其结局来看,大革命未给大多数人带来好处,也沒有如承诺的那样给法国人带来稳定有序的自由平等博爱与民主,而是把法国人从传统与社会中连根拔出抛到无尽的困扰与动荡不安之中,共和国找不到自己坚实的根基。但为世界都市的巴黎却成为由报刊、小册子、俱乐部、社团与咖啡馆等形成的两个世纪的舆论中心,各类狂想家在这里摇唇鼓舌,舞文弄墨,都会聚集起自己的同志和战友。无政府主义、社会主义、共产主义的各类学说大多是在巴黎传播出去的,也是它们的发源地。巴贝夫、邦纳罗蒂、圣西门、傅立叶、安凡丹、勒鲁、卡贝、布朗基、路易-勃朗、毕舍、浦鲁东都有大量的追随者和实践者,马克思博士也是在流亡巴黎时自觉地选择共产主义的,因自视有德国哲学的批判头脑,马克思以共产主义宗师炫世。

二十五

马克思与恩格斯选用共产主义作为自已政治社会学说的标记是基于内在的思想逻辑,以区別于各式各样的社会主义学说与流派。马克思自诩其对共产主义的最大贡献是为闵采尔-巴贝夫系列的行动的共产主义确立一个科学的基础,并把这种共产主义的普世理想变为一种普世的国际主义运动。马克思学说从其诞生之日就如同他批判的资本主义一样自觉是一种普世的超越民族地域界限的国际思潮与运动。马克思学说的秘密不在其劳动价值论的经济学说中,而在于其根植于德国思辦哲学的世界体系,而对自十七世纪英国以自然神论和有限理性为特征的启蒙学说与十八世纪战斗的俗世的无神论的法国启蒙学说的德国批判,从浪漫派到世界历史的终极史构思的思辨哲学,又源自于欧洲中古时期日耳曼民族的神秘主义。检讨应从这里开始。地狱的深处才有天堂的幻想。

二十六

苏联斯大林版的马克思主义创造史之经典叙事是一个固定的模式,几乎适用于一切民族与一切国家,即知识阶层的共产主义思想是从资产阶级自由主义途径资产阶级激进民主主义转变为无产阶级共产主义一一马克思主义,假如在这个进军中不误入各类空想的社会主义共产主义迷途的话,都会修成正果。其实,这就是马克思在清算德意志意识形态时发现的一个定律:所有时代的统治思想不过是统治集团或符合统治集团利益的思想。还应指出,马克思指控法德的“资产阶级”主要是君主专制制度中的官僚寄生阶层。就在马克思与魏特林在1846年为共产主义策略争论不休的时候,蒲鲁东代表巴黎提出了这样的倡议:“我们不要把自己树立为新的不宽容的主人吧,我们不要成为新宗教的信徒吧,尽管这种宗教可能是一种逻辑的或理性的宗教。”那么,马克思与德意志意识形态究竟是一种什么关系呢?

二十七

德国思辨哲学-德意志意识形态的源头活水一直溯源到9世纪的修道院院长拉班-莫尔,他认为世界就是有关圣灵的巨大隐喻,而所有的知识仅仅是找出证据肯定信仰。拉班-莫尔被誉为“日耳曼先师”。十三世纪的大阿尔伯特与十四世纪的艾克哈特发展了德国神秘主义的思维方式一一辩证法,从艾克哈特大师的讲道之中呈现了黑格尔讲演录中的辩证法的最初形态:对上帝的认识,都只有通过灵魂的自我遗弃才能获得。也就是唯有上帝自身的自我遗弃才有可能。思辨的神秘主义,通过十五世纪红衣主教库萨的尼古拉发现的对立统一观念与异化,十七世纪的鞋匠雅各-波墨揭示了存在的“巨大奥秘”:自我显现。存在只有在与之对立的“镜子”中才能被反思。上帝的自我设定(正题),只能是对它自身和它自身的对立面(反题)的综合(合题):真正的“是”,即“是”与“否”的合一。这就是辯证法的《大秘密》。

二十八

从十七世纪德国百科全书式的思想家沃尔弗到十九世纪的德国思辨哲学的最大代表黑格尔,完成了一个庞大而精密的思辨体系,其核心是否定之否定的辩证法。马克思自称从头足倒立的德国哲学中抢救了辩证法,并以之为现实世界的运行法则,为共产主义确立了牢固不拔的科学基础。而中国的顾准,在那个狂乱蒙昧的岁月中,却通过马克思同时代的工人哲学家狄慈根提供的线索,认定所谓辩证法就是共产主义的神学。这一石破天惊的洞见足以使智慧的顾准达到当世顶级思想家的水平。无怪乎我所敬佩的先哲李慎之先生倡议建立一门“顾准学”。中国,只有从理性思维中走出辩证法的困境,才会真正有科学与科学创造的春天,才会与现代世界主流接轨。这是当世中国新启蒙的首要责任。

二十九

对马克思而言,在其将辩证法嫁接在法国唯物主义的粗足之后,就既超越了黑格尔,又超越了狄德罗与费尔巴哈,辩证法不再是一种方法,而是现实与知识的真实法则,人类历史将循着否定之否定的法则从原始共产主义经过阶级统治的社会达到高级阶段的共产主义,马克思从大英博物馆的英国古典经济学文献中汲取并征引了巨量的知识材料只为了证实他发现的这一人类历史规律的辩证法。马克思的主要著作《资本论》在他生前只发表了第一卷,恩格斯后来依据其手稿整理出版了第二、第三卷,三卷对资本主义消亡的论证是互相矛盾的,第一卷是资本集中,第二卷是平均利润率,第三卷是工人阶级“贫困积累”的绝对贫困趋势。现代社会的运行是与《资本论》描述的趋向背道而弛的。而马克思沉迷的辩证法并不足以为科学的根据或前提,如雅科夫列夫所断言,实质上,马克思据以建立其科学社会主义世界观大厦的全部具体经济结论没有一个是在实践中得到证实的。庞巴维克在《卡尔-马克思及其体系的终结》对劳动价值论予以有力驳斥。马克思学说仍是前社会科学的德意志思辨。科学共产主义并不科学。

三十

对于资本运动的分析,马克思从黑格尔《逻辑学》的概念三段论中取得灵感,把黑格尔称作“概念的运动法则”转换为人类社会的历史运动,而“否定”这一“辩证法的灵魂的源泉”被视作阶级斗争,把否定的法则运用于资本与雇佣劳动的关系,设计了现代社会矛盾的历史过程:“从资本主义生产方式产生的资本主义占有方式,从而资本主义的私有制是对个人的、以自己劳动为基础的私有制的第一个否定。但资本主义生产由于自然过程的必然性,造成了对自身的否定。这是否定的否定。这种否定不是重新建立私有制,而是在资本主义时代的成就的基础上,也就是说,在協作和对土地及靠劳动本身生产的生产资料的共同占有的基础上,重新建立个人所有制”。辩证逻辑导致了资本的否定与自身否定。恩格斯称马克思发现了“现代资本主义生产方式的特殊的运动规律”。

三十一

当代马克思学研究有一个重要发现,马克思本人认为他的著述是也仅仅是实际社会运动的理论表现而不是甚么指导思想,马克思是以他理解的科学立场对待他的思想的,故其生前断然宣布:“我只知道我自己不是马克思主义者”。这记载于我少年时代反复研读的梅林《马克思传》中。顺便说一句,梅林的《马克思传》告诉我拉萨尔是唤醒德国工人运动的真正领袖,这在那个教条主义的全面专政年代,是一种国际共产主义运动史的启蒙。恩格斯讲“马克思主义”是马克思的法国论敌滥用的。不幸的是,为了提高马克思学说的权威性,恩格斯采用了为马克思论敌杜撰的“马克思主义”,从而实际上成为马克思主义学派的创始人。当拉法格忧虑“马克思派”可能沦为一个“宗派”时,恩格斯答称“我们一直称你们为’所谓的马克思派’,没有用过別的称呼……如果你们另有同样简单的名称,请告诉我们,在适当的场合我们也乐意使用。”

三十二

十九世纪五十年代到八十年代,马克思为欧陆政府放逐而寓居英国的时候,完全有机会观察到英国工业化进程中工人状况的改善,而并不是如《共产党宣言》描述的那样“贫困也愈来愈严重”,在他指导第一国际的岁月里,始终不同意发行《共产党宣言》英文版,马克思以为这本小册子并不适于英国工会主义者阅读。马克思把革命的希望寄托于他在著述中理想化的歐陆工人阶层,而马克思历史社会学的核心观念一一生产力水平对于社会变革的主导作用一一则不见于《共产党宣言》。伯恩施坦指出,马克思的政治错误源自他理论的根本缺陷,即从黑格尔那里引入的辩证法。如果不是列宁与列宁主义的俄国革命与共产国际,马克思学说可能仅仅是欧美大学课堂上一种如孔德与韦伯那样的社会哲学学说。1992年《马克思恩格斯全集》历史考证版的陆续问世,似乎表明马克思从东方的庙堂又回到了西方的研究所。

三十三

马克思的辩证法显然不是苏格拉底于对话中发现矛盾的形式逻辑,而是源于前苏格拉底哲学家赫拉克利特的流变观念。伯恩施坦在与考茨基讨论时,正确地指出辩证法的危险性是对特殊事物不恰当的抽象,且在思维方法上是漠视形式逻辑的命题的。伯恩施坦还指出,《资本论》是一部具有高度倾向性的斗争著作,在其编写上不可能是对细节的客观叙述。伯恩施坦说:“我是一个熟悉这部著作至今几乎20年的人,我相信我多少还能够分辨,它在什么地方和多大程度上符合上述要求,在什么地方倾向或辩证的结构使他的著者丧失了科学的客观性。在马克思的《资本论》中出现了种种自相矛盾,他往往忽视他自己确认过的重要事实,这根本是无法再否认的……”伯恩施坦称“我不认为对立面的斗争是一切发展的动力,相似的力量的合作也是发展的一个巨大动力”。

三十四

恩格斯在与杜林的论战中,宣称“论战转变为……辩证方法如共产主义世界观的比较连贯的阐述”,因为对恩格斯而言,以往全部哲学只有形式逻辑与辩证法留存下来,而辩证法则以现代科学的观点说明“相互作用是事物的真正的终极原因”,这可能是恩格斯对“思维着的理性”的最后意见。无论如何,伯恩施坦关于辩证法的批评意见是值得重视的:“不管事物在现实中是什么样子,一旦我们离开了可以凭经验确认的事实的土地并且超越这些事实而思考,我们就要陷入派生概念的世界,而如果我们然后遵循黑格尔所提出的那个样子的辩证法规律,那么我们就会不知不觉地进了“概念的自我发展”的圈套。黑格尔的矛盾逻辑的巨大科学危险就在于此”。辩证法与科学的理性思维难以相容,而通过辩证法,马克思主义与布朗基主义走在了一起。

三十五

恩格斯遗嘱的执行人伯恩施坦对马克思学说的审慎批评开启了社会民主主义的方向,现代社会民主主义在多大程度上受益于伯恩施坦,是一个有待估量的问题。而在列宁-毛泽东的共产主义谱系中,伯恩施坦则无可置疑是马克思主义的最大叛徒。伯恩施坦本人亦承认马克思的革命急进性更类似列宁的布尔什维克,但伯恩斯坦确是从马克思学说的内在逻辑批评马克思主义的。伯恩施坦深刻地洞悉马克思对现代社会的全部理论奠基于劳动价值论与剩余价值论之上。而取自洛克和斯密李嘉图的劳动价值学说“只有作为一个纯思辨的公式或一种科学假说才能要求被接受”。伯恩施坦对马克思学说之根本一一价值理论作为“一个纯抽象概念”的是否科学性的质疑,是其修正马克思主义的基本依据与基本出发点。也因这种修正,马克思依照辩证法原理精心构筑的整个资本体系摇晃起来了。

三十六

在讲巴枯宁-列宁之前,再说说老修正主义者伯恩施坦。对马克思剩余价值学说的批评,伯恩施坦实际上否定了绝对贫困化观点,认为工人工资的增长使工人状况不断改善从而参与社会财富的再分配。欧洲议会民主的发展逐渐消除了国家的资产阶级性质乃至使其”萎缩”,也就不必以无产阶级革命颠覆国家以建立独断的无产阶级专政。因为社会民主是社会不断改善的渐进和平进程,也不必总是预言落空的革命。他以为近世欧洲有社会主义的两大流派,一是以建设为目的,通过提出改革建议促进和平进化,一是从革命的人民起义汲取灵感的启示,本质上以破坏为目的,在其表现上是密谋的、煽动的、恐怖的。而凭籍革命暴力解决政治与社会问题,是进化途程中的“政治返祖”,在政治上重返野蛮。“阶级的专政必须看做是一种倒退或政治的隔世遗传”。总之,不断改善工人生活与文化状况的进化过程才是一切,最终目标是微不足道的。伯恩施坦彻底埋葬了千禧年共产主义。

三十七

巴枯宁是漫游欧洲的职业革命家,与马克思是老友,也是宿敌。在第一国际的活动中,巴枯宁创立了秘密的无政府主义国际。克鲁泡特金称巴枯宁与他是“无政府主义共产主义者”,是贴切的。巴枯宁的理论围绕着人与国家之对立这个主题,抨击所有国家组织都是强制性的,实质是人为的压迫工具,是某些人为了通过武力或神权的欺骗手段对他人行使权力制造出来的,尤其是中央集权的专制主义国家。在巴枯宁为和平与自由同盟拟定的宣言称“同盟反对以任何类型的专制权力进行社会改革的一切尝试。”甚至各种形式的“民主集中制”,巴枯宁也以为这种制度会使普通人民沦为独裁者或官僚的棋局中的小卒。对巴枯宁而言,他所珍重的是自发的自然的社会组织,如俄国的村社与城市的協作组织,人始终是在社会中生活的,自由公社是基础。未来的欧洲是不分国界由自由公社组成的联合体。他主张财产集体所有制与“各尽所能,按需分配”。对于国家,或许可提供某种安全,却绝无可能提供自由。巴枯宁称:即使国家由工人来领导,他们很快也会变得像他们所推翻的暴君一样腐败和专制。

三十八

巴枯宁与马克思互骂对方为“恶魔”,有误会的因素,有思想的争论,也有权力的角逐。巴枯宁的不幸是与不泽手段无视任何道德准则的俄罗斯青年恐怖分子涅恰耶夫的短暂合作。本來,巴枯宁在《国家政权与无政府状态》中一贯是坚持非暴力反集体的自我组织秩序的。涅恰耶夫就是陀思妥耶夫斯小说《群魔》里的主人公。他是一个狂热的革命者,对巴枯宁吹牛说他组织了一个遍及全俄的地下革命组织,诱使巴枯宁合作编写了《革命问答》的小册子,严重玷污了巴枯宁的声誉,也使马克思有理由认定其是彻底的虚无主义者。这本后来被奉为革命圣经的小册子称真正的革命者“蔑视和憎恨目前各种形式和动机的社会道德,他认为一切促成革命胜利的东西都是道德的”,“他必须用对革命事业的酷爱去消灭亲戚、友谊、爱情、感恩,甚至还有荣誉等一切软绵绵的、使人丧失力量的情绪”。涅恰耶夫后因谋杀了一个对其“革命委员会”有所怀疑的同志而最终囚禁于沙皇的彼得-保罗要塞。

三十九

无论马克思与巴枯宁如何相互谩骂诽谤,其共同点是对革命的崇拜。法国大革命的雅各宾派是革命的先驱。“没有恐惧,美德是无力的。”他们的革命意义如末日审判一样能够创造新人,只有革命才能洗刷旧制度与旧社会给予被压迫者的肮脏东西。也只有革命才能实现他们期盼的共产主义社会。如马克思所言:“这种共产主义是完美的自然主义,也就等于人文主义,正如完美的人文主义等于自然主义。由此便化解了人与人之间、人与自然之间的冲突,真正解决了存在与本质之间的矛盾,客观性与自我活动之间的矛盾,以及自由与必然、个別与种类之间的矛盾,人成为历史中已经得到了解答的谜,而且人知道他自己就是那个答案”。恰为当代马克思学家吕贝尔称,马克思学说是最彻底的乌托邦主义。而这样的主义被列宁树为放之四海而皆准的普遍真理的信条。雅科夫列夫说:其实可怕的并不是乌托邦本身,而是那种企图把乌托邦纳入社会制度的实践。

四十

与马克思巴枯宁魏特林同时代的,还有英国欧文的共产主义试验。欧文是自力奋斗成功的企业家,对工人尤其孩童的悲惨处境观察较实,他认为环境对人的影响是主要因素,“工人失业,贫穷,经常负债,他们常常酗酒并且以偷盗为生。他们习惯说谎和吵架”,穷人的孩子们比狄更斯小说描写的状况还差。欧文游说政府通过了工厂法案,限制工时。他推动建立国家救贫体系,使老有所终幼有所养。他认为应扩大消费,使它与生产平衡,普及教育,消除愚昧。他资助创办了乡村免费小学,试办公社,从罗契台尔先驱者合作社到奎因伍德公社。他起草的“致拉纳克郡报告书”启发了傅立叶。后来他远赴美国投巨资创办了印第安那州雷普社团的和谐区。欧文的努力为人称道,有德国纯朴的农民雷普信徒1814年到美国购荒地三万英亩,欧文为之规划,形成了兴旺的共产试验区,但仅三年就失败了。回到英国的欧文,参与了争取工人普选权的宪章运动。

四十一

十九世纪后三十年到二十世纪初,以马克思恩格斯为代表的欧洲社会主义者普遍认为俄国罗曼诺夫家族的沙皇统治是全欧的反动堡垒,俄国将爆发一场推翻罗曼诺夫王朝的1789年法国式的民主革命为共产主义清除障碍,而在俄罗斯,沙皇统治被称为“各族人民的监狱”,其时俄国发生了由革命的民意党人策动的针对沙皇统治集团的暗杀活动,是这种民主革命的征兆。列宁创立的布尔什维主义,就是吸收布朗基与民意党人的组织经验与策略,以一种高度集中的秘密的职业革命政党实践马克思设想的无产阶级专政。列宁在与司徒卢威争论时称“恐怖手段是一种进行政治斗争的方法”。社会民主党在原则上并不否定恐怖手段是一种斗争方法。目的是主要的,每一种斗争方法的好坏,要看它在当前条件下是有助于达到目的,还是相反,偏离目的。布哈林称要“有组织地削弱文明”。

四十二

涅恰耶夫事件是俄国革命的先兆。洞彻世道人心的俄罗斯作家陀思妥耶夫斯在1873年发表的长篇小说《群魔》,以预言家的冷酷想像力描述了五个阴谋家如何以全世界平等的信念开始并以对全世界的奴役为终结。被特卡乔夫称为“我们现代青年典型的代表”涅恰耶夫被审判与被监禁不是事件的结束而是开端,未来的俄国革命将充满涅恰耶夫事件。《群魔》里的涅查耶夫化身曾有一段对革命后他要创建的社会的独白:“社会的每个成员必须监视他人并揭发他人,所有的人都是奴隶,他们作为奴隶是平等的……只有那些天分更高的人才能获得更高的科学和能力水平,而我们不需要更高天份的人。有更高天分的人总是手握权力,而且是暴君……他们被抛弃或被处决,西塞罗的舌头被割掉了,哥白尼的眼睛被挖出来了,莎士比亚被石头砸死了”。这不是小说,是苏维埃共产主义的实践与现实。20世纪20年代,俄罗斯流传着一个为陀思妥耶夫斯基树立的纪念碑:献给费多尔-陀思妥耶夫斯基,来自心存感激的恶魔。这也是斯大林时代查禁陀氏作品的原因吧。

四十三

巴枯宁与涅恰耶夫创作的《革命问答》,又译《革命者手册》、《革命者教义》,加缪称其“把革命的权术提高到至善的高度,而把所有的道德考虑都撇在了脑后,为了革命的利益,为了他自己断定的定义,所有的行为都是正义的,所有的罪犯都是合法的,无论它们是多么令人作呕。”巴枯宁认为,俄国的革命者要与匪盗世界联合起来,因为后者是天生的政府反对派。涅恰耶夫讲“我们的任务是破坏,猛烈地,彻底地,普遍地,而且是无情地”。对自由派,革命者必须假装盲目地跟从,但实际上将他们纳入到控制之中,掌握他们的秘密,使他们无路可退。革命者“无论白天黑夜,他必须只有一个念头,一个目标一一无情地破坏。冷酷无情、不屈不挠地向着这个目标前进,他必须时刻准备献出自己的生命,用自己的双手消灭所有障碍……革命组织须编写一个应该被消灭的人的名单……首先,他们必须消灭那些对革命组织极其有害的人。”雅科夫列夫称涅恰耶夫是布尔什维克的先驱。

四十四

车尔尼雪夫斯基的小说《怎么办》使列宁觉醒为一个革命者,这部小说中的一个特殊材料制造的革命主人公一一拉赫美托夫也激励了涅恰耶夫,是涅恰耶夫崇拜的偶像。涅恰耶夫在《革命者手册》中设计了夺取国家政权的精干革命组织的架构,其组织原则是“服从,服从,再服从一一无条件服从”。要使服从渗透到追随者的血液里。涅恰耶夫将其革命团体分为一级革命者和二级革命者。为了革命的需要,一级革命者可以把二级革命者当作资本加以利用。如果一个一级革命者决定牺牲一个二级革命者的自由甚至生命,那也是他的无可非议的权力。革命组织必须想方设法全力促进社会的灾难与罪恶加深,逼迫人民失去耐性而自觉地起来暴动。涅恰耶夫谋划开展一场全俄的兵变以埋葬罗曼诺夫王朝。有人问他革命中多少人会死亡时,涅恰耶夫笑着说:“我们应考虑有多少人能活下来。”他的朋友也是诗人的塔卡切夫写道:“现在,我们需要大斧,我们需要利刃”。

四十五

布尔什维克的前驱是民意党。这是俄罗斯本土从暗杀沙皇集团百炼成钢的革命恐怖分子组建的秘密革命团体,与《革命者手册》的组织原则大体一致。它的最高领导机构是执行委员会,党的所有成员必须把他们的全部财产和生命都贡献给权力无边的执行委员会,一旦入党,绝不准自行退出或脱离,党的所有成员必须无条件地忠诚地遵守执行委员会的一切决定。执行委员会由十一人组成,他们配备级別不同的特工供其作为革命资本加以利用,“执委会的特工是由执委会指定的,只有义务,没有权利”。执委会选出三人组成行政委员会,在执委会闭会期间行使绝对的权力。党的主要目标就是以无情的不间断的恐怖行动推翻现存的政权。这就是1879年利佩茨克会议的结果,一个纪律严明的新型政党在沙皇的土地上诞生了。俄国马克思主义之父普列汉诺汉曾经是民意党前身土地与自由社的重要成员。列宁的胞兄亚历山大也是民意党人。

四十六

旧俄时代的革命悲剧与民国时代的革命悲剧相同,革命的激进主义是以突出夸大社会经济问题的严重性尖锐性危机性而忽略乃至阻碍了打断了国家的立宪进程,对未来的幻象冲淡了实际相关的问题。德国史家施拉姆指出:俄国革命者“以一种正是被悲哀的现状和每日的危险激励的末世幻想,梦想着能够担当起全世界范围的拯救者角色。他们认为自己受托开启拯救全人类行动的序幕”。也就是说,他们将自己视为所有人民解放者的意义探求并为了使自己的生活更有超越性和更有意义而把自己的民族自己的国家引向万劫不复的深渊。屠格捏夫讲人们难以断定这些左派革命者是傻子还是圣人,而有人认为两名的混合正是俄罗斯所需要的。从民粹派到民意党,车尔尼雪夫斯基和涅恰耶夫是后者的理论家和实践家,将这条革命激进主义进行到底的是二十世纪共产主义的创造者一一列宁。

四十七

列宁为现代共产主义确立了一套组织原理,以此操纵并领导了最为广泛的群众运动,成功地在俄罗斯夺取政权且把共产主义的组织体系转换成政权体系,还创建了推进世界革命的组织中心一一共产国际。列宁与列宁主义的政党政权成为现代共产主义的主要特征,主要的识别标志。列宁以马克思主义的完整学说为这一共产主义系统的不容讨论与批评的信条。虽然巴贝夫首创了无产阶级专政的概念并于法国大革命中喊出了“工人共和国”的口号,如考茨基所言,巴贝夫被处决了,“他的以无产阶级代言人的专政作为实现社会主义的唯一工具的概念,并没有随他一起死亡”,马克思博士为共产主义提供了德意志传统的百科全书式的知识综合,使这一为欧陆统治集团感觉恐惧的战斗思潮具有了规范化的完备的理论体系并以第一国际的联合组织影响了各国的工人运动与革命运动。共产主义也由游荡的幽灵现身为“用暴力推翻全部现存的社会制度”的共产主义革命。

四十八

共产主义信条有两大要义,一是《共产党宣言》声称的共产主义之全部纲领是消灭私有制,主要是现代资本的私有制。马克思的政治经济学尤其是《资本论》第一卷提供了资本集中到垄断的全部分析,故断言资本的私有制几乎吞噬了全部的社会财产与个人财产。二是通过无产阶级的阶级斗争建立无产阶级专政。后者是一个消灭阶级的过渡阶段。列宁在《怎么办》中为共产主义补充了两个要点,一是无产阶级的阶级政治的意识是共产主义专业知识阶层从外面灌输进去的,普列汉诺夫也有此类意见。二是无产阶级政党必须接受集中化、秘密化和专业化的组织要求与严格训练:“我们运动中的活动家所应当遵守的唯一严肃的组织是:严守秘密,极严格地选择成员,培养职业革命家。”列宁的集中制政党思想是布尔什维主义的核心意义。

四十九

列宁的先锋队政党自己赋予自己合法性与合理论。因为依据列宁的理论,只有布尔什维克的政治精英才能使工人阶层真正认识自己的利益、自己的意愿与自己的目标,才能使工人阶层成为工人阶级从而意识到阶级革命的条件、战略与策略,布尔什维克是无产阶级的先知和代表。因为布尔什维克掌握了马克思主义,掌握了人类历史的发展规律,掌握了社会科学的真理。马克思主义是布尔什维克合法性的根源。而无产阶级专政只有通过共产党来加以实行,“无产阶级还都是那样分散,那样被人鄙弃,在某些地方还受人收买……以致无产阶级专政不以直接由包括全体无产阶级的组织来实现,只有吸收了阶级的革命力量的先锋队才能实现这种专政。”没有无产阶级的先锋队政党,便不能实现无产阶级专政。所以,列宁的政党与政权首先是意识形态政党政权。

五十

与意识形态首要地位相称的,是列宁对政党规定的高度集中高度集权的组织原则。“组织能使力量增强10倍”。党必须拥有高度纪律的权威中心,必须用一种声音讲话,统一于领袖的意志。党内决不能容忍政治反对派,必须利用国家力量镇压反党反社会主义的一切活动。列宁写道:“专政的科学概念无非是不受任何限制的、绝对不受任何法律或规章約束而直接依靠暴力的政权”。考茨基批评说:“列宁要求全体工人阶级都温顺地服从他的领导。党内如果有人对別的领导表示更大的信赖的倾向,或者为自己的见解辩护,就会被列宁认为是死敌,要用一切手段和他们进行斗争”。考茨基讥嘲说:“象一神教的神一样,独裁者是一个非常嫉妒的神。除他自己以外,他不能容忍有別的神存在”。中国的古话是:天无二日,民无二主。

五十一

专政的治理何以立竿见影?俄罗斯讽刺作家谢德林透露了其秘不示人的规则:“掌握尽可能多的恶棍,因为一般老百姓都忙于自己的事情,而恶棍们都是些无所事事的人,能干各种坏事……”,对于长官何为人间祸害的询问,恶棍们对长官说:“我们的纲领应该是这样的:只许我们恶棍们说话,而其他人都闭嘴,我们这些恶棍想起来的主意或建议必须采纳,而对其他人的愿望则置之不理……让我们这些恶棍们受到无微不至的爱护和照料,而给其他所有人都戴上镣铐。把我们恶棍所做的坏事看成是好事,而其他人即使做了好事,也应把它说成是坏事。还应做到,没有人敢说我们这些恶棍一句坏话,而我们这些恶棍想要骂谁就骂谁!”唯有如此,才会有真正的祸害。

五十二

列宁在《火星报》时期公开使用“无产阶级专政”这个关乎俄国未來革命的关键用词时,即遭到社会民主党内马尔托夫等人的质疑。马尔托夫质问无产阶级专政是以谁的名义行使的,列宁的党称其代表无产阶级,又不属于无产阶级,因列宁称无产阶级不可能自发地生成阶级革命的意识,那么,马尔托夫指称列宁的党只代表它自己而缺少真正的社会基础,必类似法国大革命恐怖时期的雅各宾派。一个沒有真正社会阶层基础的政党夺权执政,只会重演恐怖统治的旧戏,最后的结局是革命的朋友与敌人同归于尽。这是所有自上而下的暴力革命的危险所在。考茨基指出,只有从属于社会的国家机器才能成为解放无产阶级的手段,而无产阶级专政使国家凌驾于社会之上的这种情况发展到顶点。

五十三

列宁在沙皇专制的警察国家以军事化原则创立的革命政党在国际范围内社会民主党左翼也引起了尖锐的批评。卢森堡称:“在一部分俄国社会民主党人中,这样迫切地试图通过无所不知和无所不在的中央委员会的监管,以防止充满希望的、生气勃勃的俄国工人运动出现失误,我们知道这就是一再同俄国社会主义运动开玩笑的主观主义……但是现在,这位俄国革命家的’自我’迅速把事情颠倒过来,再一次宣布自己是历史的全能舵手一一这一次是以社会民主工人运动中央委员会主宰者的身份出现”。的确如此,中央委员会有多大权力,完全由党的领袖说了算。而党的领袖又通过中央委员会强制推行其各项政策,所谓民主集中制,仅仅是最高层极少数寡头领袖的協商与自上而下征求意见而已。各基层支部只是执行上级意志的工具而对决策无发言权。党内民主难以逾出中央委员会的范围且这个范围的民主亦取决于领袖的意志而非制度化的安排,即使在革命成功以后。

五十四

列宁政党的组织原则在《怎么办》中浓缩为下面一段文字:“由最可靠、最有经验、经过最多锻炼的工人组成的一种人数不多的紧密的核心,它在各主要区域都有自己的代表,并且按照严格的秘密工作的种种规则同革命家组织发生联系一一这样的核心在群众最广泛的支持下,不必有详尽周密的规划,也能践履一个工会组织的一切职能,而且还能够以社会民主党人所期望的那种方式去践履这些职能”,其实践的结果,如列宁的十月起义的战友托洛茨基在1904年所批评:“党的组织取代了党本身,中央委员会取代了党组织,而最终独裁者取代了中央委员会”。又如罗莎-卢森堡所批评,列宁所谓的“无产阶级纪律”其实就是由中央委员会施行的纪律,而不是“社会民主主义的自愿的自律”。考茨基指出:“无论什么时候。只要独裁在党的机构内掌握了权力,那个机构就必然会在精神上堕落下去,因为独裁势必使最优秀的分子或者堕落下去,强迫他们放弃自己的独立,或者把他们驱逐出党”。

五十五

列宁的政党理论为美国政治学家亨廷顿称为二十世纪政治组织学与政治控制的重大发明,因其建立的政府为有效控制的政体。亨廷顿说:“共产主义最有关的特点是它的政治理论和实践,不在于它有马克思主义,而在于它有列宁主义……对马克思来说,关键是社会阶级,而对列宁来说,关键却是政党”。列宁政党有三大不变的意识形态要素:其一,马克思主义是永恒的教义,代表了人类认识的真理,尤其是反映客观真理的辩证法,是打开世界一切玄秘的钥匙,是科学的科学。马克思主义的权威解释权为党的领袖。其二,党由人类自我选定的最优秀最革命的一小部分先进分子构成其核心骨干,在道德与智慧上因精通马克思主义而有特殊的优势,是经过千锤百炼千挑万选中产生的英明领袖并有洞见未来洞察一切的智力与能力。其三,党是一个严密的自上而下控制的中央集权的组织体系,所有的普通成员都必须服从严格的纪律,各级领导人也必须严守他们在等级权力制中的职责与规则。党的决定必须为全党不折不扣加以执行。党员的绝对服从与党员领袖对马克思主义的绝对忠诚,是列宁政党的绝对要求。列宁认为,只有这种精神上的高度统一与组织上的高度一致才能夺取政权。

五十六

列宁的布尔什维克在十月政变中夺取政权后,建立了党治国家的集权政体。在列宁的坚持下,夺权前布尔什维克改名为共产党。列宁称:“我们共和国的任何国家机关未经党中央的指示,都不得决定任何一个重大的政治问题或组织问题”,从这个意义上说,“无产阶级专政实质上是无产阶级先锋队的专政”,即党的专政。党将自身的组织原则推广为政权组织之原则,党之组织亦为苏维埃政权之核心部分,党的信条成为国家意识形态。1919年,列宁发起创立了共产国际,如曾任共产国际主席的季诺维也夫所言,第三国际或共产国际是要建立一个单一的由各国共产党支部组成的实际集中控制的世界共产党。其目标是推动世界的共产主义。加入共产国际的各国共产党必须布尔什维克化,即按照俄共(布)的组织原则加以构建并受共产国际之决议决定的统一指导。共产国际与苏联的扩张,标志着地球将有半数人口卷入的国际共产主义体制的兴起。斯大林完全继承了列宁的政治遗产。二十世纪二十年代的苏联被列宁看成是世界苏维埃共和国的样板,也成为共产主义革命与建設的中心。

五十七

曾任苏联共产党宣传部长的改革家亚-尼-雅科夫列夫称,布尔什维克革命及以后的不幸是“涅恰耶夫精神在列宁的实践中牢固地得到了确立”,是因为列宁彻底抛弃了改良主义。因此,恐怖统治是共产主义方法的必然结果。考茨基称:“布尔什维克政权所结的果,就是建成了一种新的阶级统治。……它们是从布尔什维克专政的条件下必然地产生出来的……它的最终的共产主义目标,也越来越成为装饰品了,仅仅成了一种记忆,或是作为诱骗社会主义的理想主义者们的工具,因为独裁者是要想利用这些理想主义者来达到自己的目的的。”对于夺权后仍严肃对待共产主义的反对新特权的老布尔什维克,或被监禁、放逐,或被沉默,或束手无策,还有不少被处决了,而“多数老布尔什维克已经向独裁者屈服了,已经从革命者的水平堕落到谄媚的廷臣的地位……取得和保持这些特权就是他们唯一的目的。”

五十八

1919年2月社会党国际通过的谴责布尔什维克的无产阶级专政与赞同议会民主的布兰亭决议案,意味着社会民主主义与共产主义的决裂,也表明两造的核心分歧是民主与专政问题。也就是说,社会主义的基本政治制度是议会民主制还是无产阶级专政,这是社会民主主义与共产主义的根本区别。列宁发起的共产国际邀请书中附有一个15条纲领草案,其要点是普遍建立无产阶级专政,规定新国际应名为“共产国际”,其基本原则是“每个国家里的运动的利益,应服从于整个国际革命的普遍利益”,共产国际不是以前各国独立政党之间的松散联盟,而是指导世界革命运动的集中控制的权力中心。1919年3月在莫斯科召开的共产国际代表大会发布了列宁、托洛茨基、季诺维也夫等五人签署的宣言,称各国共产党必须完全服从共产国际的决定,号召“团结在共产主义的旗帜之下”。宣言称共产国际是实行集中制的领导机构,即“国际共产党”,其目标是领导世界革命,“把整个世界变成一个合作联邦,从而实现真正的人类友爱和自由”,这个联邦就是“工人苏维埃的国际共和国”。

五十九

列宁在共产国际成立大会上要求各国“实行无产阶级专政的苏维埃制度。”会后,列宁在《真理报》撰文称:“第三国际即共产国际的成立是国际苏维埃共和国即将诞生的前兆,是共产主义即将在国际范围内取得胜利的前兆。”列宁在为1920年6月召开的共产国际第二次代表大会起草的《加入共产国际的条件》中规定“共产国际代表大会及其执行委员会的一切决定,所有加入共产国际的党都必须执行。”列宁写道:“一切愿意加入共产国际的党,都应当更改自己的名称。凡是愿意加入共产国际的党都应该称为:某国共产党(第三国际即共产国际支部”。各国共产党作为共产国际支部都必须绝对服从共产国际及其执行委员会的领导。列宁要求通过联邦制在全世界推广苏维埃制度,把一国的无产阶级专政“转变为国际的专政”。

六十

1920年7月19日到8月17日,列宁在莫斯科召集了共产国际第二次代表大会,季诺维也夫为共产国际执行局主席。季诺维也夫在开幕词中称“两三年内整个欧洲就会苏维埃化了。”列宁称共产国际“已经不是宣传家的協会,而是世界范围内开始准备的实际作战大军的总和”。其时,托洛茨基、斯大林正在指挥红军攻打波兰,伏罗希洛夫致信斯大林“我们消灭了大量波兰人……砍杀和消灭的共有两万人”。列宁要求在已被红军占领的波兰地区建立俄国式的苏维埃和革命军事委员会,并策动意大利、匈牙利、捷克、罗马尼亚的起义,以加速世界革命的进程。红军兵败华沙,被俘达6万5千人,人称“维斯图拉奇迹”。波兰保住了欧洲,列宁的世界革命受挫,托洛茨基说:“当我们梦游般的状态下逼近华沙时,那里并没有革命的高潮……其结果出现了我们曾经在我们的军事战线上经历过的最重大的灾祸之一。”苏波战争后签署的《里加条约》划定的苏波边界线维持到1939年。

六十一

列宁托洛茨基的世界革命计划受挫于苏波战争。在共产国际第二次代表大会上,列宁在《关于国际形势和共产国际基本任务的报告草案和提纲初稿》中称“要利用危机进行革命”,战争创造了革命的条件,如世界大战触发了俄国革命一样,对波战争将引爆欧洲的革命。对波战争期间,在波兰的东部各省成立了60多个革命委员会。与红军进入波兰的还有捷尔任斯基实际负责的“波兰临时革命委员会”,这个委员会实为俄共(布)组织指挥的波兰“流亡政府”,捷尔任斯基专注于筹组波兰红军。兵败华沙之后,捷尔任斯基的“波兰临时革命委员会”撤回了莫斯科。从此以后,列宁梦回俄罗斯,战时共产主义已是穷途末路,急待改弦更张以谋政权的生存。列宁在公开场合也罕提“世界社会主义苏维埃共和国”或“国际苏维埃共和国”了。

六十二

十月政变后,列宁的革命战略是从“一切权力归苏维埃”到“一切权力归布尔什维克”,实行战时共产主义和军事主义。曾任俄罗斯联邦总统属下的为政治镇压受害人平反委员会主席的雅科夫列夫在《雾霭》一书中依据档案资料与当事记录对十月政变后列宁的布尔什维克政党在内战中的情形做了真实报导。1918年8月捷尔任斯基称,布尔什维克负有引导和领导仇恨与复仇的历史使命。在革命后三天苏维埃政权就公布了“仇恨纲领”、“复仇纲领”、“人民公敌纲领”,12月人民委员会“宣布立宪民主党为……人民公敌”。1919年12月人民委员会成立了捷尔任斯基为主席的“革命之剑”一一全俄肃反委员会(全俄肃清反革命和怠工特设委员会,简称“契卡”),捷尔任斯基称:“凡是胆敢稍稍进行反对苏维埃政权宣传的人,都将立即逮捕,关进集中营。”季诺维也夫写道:“我们应当将苏维埃政权治下一亿俄国居民中的九千万人争取到我们这边来。至于剩下的那部分人,对他们我们没有什么可说的,应当把他们除掉。”列宁称专政为“不受任何法律约束……而直接依靠暴力的政权。”

六十三

十月政变前,高尔基在《新生活报》刊文吁求布尔什维克不要起义,否则,“群众中所有的黑暗本能就会喷发而出,因为他们早已被生活的崩溃以及政治的虚伪和肮脏所激怒了。人们将要彼此残杀,而不会克服自身的兽性”。这类警示对列宁无济于事。1918年1月列宁解散了立宪会议,他宣布:“俄罗斯共和国的全部政权属于苏维埃和苏维埃机关。因此,任何人和任何机关攫取国家政权某种职能的任何尝试,都应视为反革命行动。任何这类尝试,苏维埃政权都将使用所拥有的一切手段予以镇压,直至使用武力”。同时,列宁撰文称贯彻“社会主义全科玉律”的方法之一是“将十分之一犯游手好闲罪者处决”。1918年9月布尔什维克政权颁布《关于红色恐怖的法令》,其中称“必须通过将阶级敌人隔离在集中营内来保障苏维埃共和国的安全,所有同白卫军组织、阴谋和暴乱分子有牵连的人均应处决”。

六十四

被列宁看作“极其可憎的陀思妥耶夫斯基”曾预言俄国的革命“暴动将从禁欲主义和抢掠一切财富开始,将开始废黜宗教,毀坏神庙,将其变成兵营和畜舍,血洗全球,然后自己吓得魂不附体”,只有最后一句话错了,列宁视为“无产阶级的雅各宾派分子”的捷尔任斯基仅在1918年几个月时间就处死了5万多人,其死亡标准是其副手拉齐斯在捷尔任斯基创办的《红色恐怖》上刊文所称:“审讯中不要去寻找被告反对苏维埃政权言行的证据。您应当向他提出的第一个问题是,他的家庭出身、所受教育或者职业是什么。这些问题就应当决定被告的命运。这就是红色恐怖的意义和实质所在”。1918年底布哈林等指控契卡握有无限权力,其组织“充斥着罪犯、暴虐狂和流氓无产阶级的腐败分子”,建议应加以限制,党的监察委员会主席加米涅夫要求取消全俄契卡。斯维尔德洛夫、斯大林、托洛茨基则为之辩护。列宁把对契卡的指责说成是“来自人数有限的知识分子的责难”。列宁称“重要的是肃反委员会在直接实现无产阶级专政。”党中央决定禁止对全俄肃反委员会进行“恶意的批评”。

六十五

1923年捷尔任斯基为局长的苏维埃国家政治保卫总局发出的一个秘密通令,详细列举了要予以肉体消灭的社会族群:“沙皇机关职员”,包括所有原内政部职员和所有司法部职员。以及(1),白军、非正规白卫部队……(2),所有政府机关文职人员(3),所有宗教活动家:东正教和天主教的主教、神甫、拉比、助祭、修士、合唱指挥、教民组长,等等(4),所有原商人、商店和小铺的店主以及耐普曼(指新经济政策时期的企业主、商人)(5),所有先前曾使用过雇佣劳动力的原地主、大佃户、富裕农民。所有原工业企业和作坊的厂主(6),所有其直系亲属处于非法状态或反苏维埃的人(7),所有外国人,不论其所属民族(8),所有其亲友在国外的人(9),所有宗教教派和宗教团体的成员(特别是浸礼宗教徒)(10),所有旧学派的学者和专家,特别是其政治方向至今不明者(11),所有过去曾因走私、间谍活动等受到怀疑或者判刑的人。 这就是列宁通向共产主义的“消灭阶级”。

六十六

内战与战时共产主义造成城市的饥荒。列宁把饥荒归因于富裕农民藏粮。列宁1918年提出“掠夺掠夺物”的政策对付有余粮的农民,并组织城市工人到农村武装搜集余粮,对农民进行“十字军讨伐”,把粮食收归苏维埃政府。列宁称:“同饥荒作斗争的任务不仅是从产粮区弄到粮食,而且要把所有余粮以及各种食品全部收集起来,作为国家储备”。列宁把将从农村掠夺来的粮食由苏维埃政权统一调配称之为“这里我们正在为打下共产主义分配的基础,为真正奠定共产主义社会的牢固基石而奋斗”。1919年1月人民委员会正式颁布了《余粮征集令》,规定农民必须上交全部余粮。农民留粮的标准就是一个人生存最低限度的需要量,这个需要量在实际执行中仍会降低。布尔什维克的武装征粮引起产粮区农民的反抗与起义,图哈切夫斯基用毒瓦斯镇压坦波夫起义的农民。“窒息性毒气的气味充溢整个森林,将藏身其中的一切都消灭干净”,其后果是坦波夫森林中农民尸横遍野,惨不忍睹。如列宁所言,创立红军的目的十之八九是为了“从事经常性的军事行动,以便获取、夺回、收集与运走粮食和燃料”。1916年俄罗斯中部地区人口总数有6800万,到1920年仅剩下3800万了。

六十七

战时共产主义时期对农民的暴力掠夺与镇压是列宁执政时代极其血腥的历史篇章,对第聂伯河、顿河、伏尔加河、乌拉尔河和捷列克河一带的哥萨克居民实行了斩尽杀绝的政策,400余万哥萨克居民被镇压,几乎每个哥萨克集中区都发生了大屠杀,造成了俄罗斯历史上永久的创伤。列宁的武装征粮与斯大林“挖掉农业中的资本主义根子”的集体化是导致俄罗斯农业长期滞后的历史原因。伯恩施坦在1924年批评说:“布尔什维克的学说及其从马克思的武库里搬来的口号是一种非常粗暴化了的马克思主义,马克思主义正是要人们认识意志力量在历史上的界限,而布尔什维主义作为学说却別有用心地无视这种界限,陷入了对暴力的无限创造力的迷信,这在实践中就成了一种祸患无穷的蹩脚试验的始祖。”

六十八

列宁对俄罗斯时代最杰出的知识界代表人物采取了驱逐出国的措施。他在1922年致斯大林的便笺上写道:“要让俄罗斯长时间保持清洁……将他们统统赶出俄罗斯”。160名俄罗斯哲学宗教与社会思想顶级学者作家乘“哲学家之船”被逐出境。托洛茨基称驱逐是一种“有远见的仁慈”,因为一旦有事,他们可能被处决。布哈林1925年在《真理报》刊文称,布尔什维克夺权执政“是踏着尸体过来的,为此不仅要有久经锻炼的神经,而且要有马克思主义分析为基础的对于历史赋予我们的道路的认识”。布哈林论证了只有具有马克思主义世界观才能成为真正的学者,“要按照一定的方式使知识分子干部经受思想意识上的良好锻炼,不错,我们会像在工厂里那样制造他们。”为此,国家政治保卫总局在知识界潜伏了一张严密的谍报员网,其谍报机关定期向俄共及后来的苏共中央政治局报告知识界的思想动态。1917年俄罗斯有46名科学院院士,其中死5人,流亡8人,1923年仅余23人。

六十九

在情报机关的密报中,可以观察到作家艺术家对苏俄时代共产主义实践的真实看法,如列宁格勒的导演加夫龙斯基说,想想吧,都拍些什么电影:又是阶级斗争,又是把党的机关捧到天上。 导演别列斯涅夫说,我弄不明白艺术中的政治,我恨透了这一切。作家别雷说:“不该由暴徒在实际中运用社会节奏的思想。实际情况表明,村社、集体、个人的概念在我们这个时代是“长尾猴手中的眼镜”,“它时而拿来闻闻,时而又穿在尾巴上”……一切都带有某种愚钝、麻木不仁的色调。你对科学、世界、艺术、人的关心,在“苏联”有谁需要?……数千年来世界所关心的东西……近五年来在我国均成泡影。以法令将数千年的成就一笔勾销,因为我们正处于“前所未有的高度发展”中,然而,街上行人眼中流露出喜悦吗?这些苍白、疲惫不堪、部分已经变形、貌似野兽的面孔,包含着过度疲劳、怨恨、恐惧和互不信任。那是驯熟的野兽的面孔,而不是人的面孔”。

七十

为了扼要叙述十月革命以后苏俄社会的精神状况与文化状况,1934年苏联第一次代表大会期间秘密对外散发的一张传单透露了一些作家代表的意见:“你们都应当明白,我国处于绝对排除任何自由发表意见的境地已经长达17年了。我们俄国作家,让人想起妓女,区別仅仅在于她们出卖的是自己的肉体,而我们出卖的是灵魂。她们无法走出妓院,除非饿死,我们也是一样……我们甚至在家里也往往避免畅所欲言,因为苏联有一套连环告密制度,要求我们作出相互告发的保证……请你们相信,俄国书籍比希特勒焚毁的马克思主义书籍要珍贵得多……我们自己担心的是,再过上一两年,连格鲁吉亚的中学都没有念完的约瑟夫-朱加什维利(斯大林)将不满足于世界哲学家的称号,会要求按照尼布甲尼撒二世的榜样,至少把他当作’圣牛’……整个苏联就是一座大军营,它在等待西方燃起火焰的时刻,好用刺刀给西欧带来现代文明“顶峰”的体现一一马克思恩格斯列宁斯大林的哲学”。

七十一

在情报机关送给斯大林的告密材料中,才可见识苏俄时期诗人作家们的内在世界。如诗人杰米扬-別德内经常抱怨:“苏联的压制和恐怖,已经到了文学、科学、任何自由研究均无可能的地步……原来我一直追随的党之中,百分之九十九点九的党员都是间谍和奸细。斯大林是个可怕的人,他经常从个人恩怨出发。凡是伟大的领袖,都在自己的周围有一大批杰出的战友。斯大林有谁呢?统统搞掉了,一个不剩……”別德内批评农业的社会主义改造:“每个农民都想当上富农,我认为对我们未来,特別重要的是拥有精力充沛能干重活的农民。他们才是真正的支柱,他们才能提供粮食,可现在对于所有从流放地回来的富农,不是除掉,就是再流放……”作家革拉特科夫说:“苏维埃政权搞了25年,可直到战前人们还是衣衫褴褛,食不果腹……”。作家索洛维约夫说:“应当解散集体农庄”。

七十二

从斯大林披阅的告密材料中研究列宁-斯大林时代的苏俄社会,就会知道无论何种深重的压迫与严酷的控制,都难以泯灭人们的自由思想。且看看卫国战争时期作家诗人们的言论。诗人乌特金说:“我国的制度和德国的制度一样地可怕……统治国家的官僚将任何独立性都扼杀在萌芽状态。他们的理想是让俄国人成为统一的羊群”。诗人戈洛索夫克尔说:“苏维埃制度是专制独裁制度,经济上最昂贵和效率最低的制度,掠夺式的经济”。作家费定说:“对我来说,自从布尔什维克一来,俄罗斯的一切早就完了……在这种情况下关于现实主义的一切谈论都是伪善或者蛊惑。文学现实主义的悲惨命运在各种专政的条件下都是一样的……不要误解,当代作家都变成了留声机。按照时下的需要灌制的唱片在这样的留声机上转动,全都发出一模一样的沙沙声。”

七十三

作家什帕诺夫说:“我们都生活在谎言、装假和最可恥的看风使舵之中”。俄罗斯古典文学丰厚的人道精神和写实风格在某些苏俄作家中还是有所传承的,即使是以作家们前仆后继的殉道为代价,仍生生不息,如爱伦堡坦言,苏维埃社会的“真相是血与泪”。这种俄罗斯文学血脉的传承,使苏俄时代仍涌出了一小批如帕斯捷尔那克阿赫玛托娃格罗斯曼布罗茨基肖洛霍夫索尔任尼琴左琴科世界级作家与作品。诗人感觉到的,理论家则以理性的方式去表达。这有必要重述马克思主义的修正主义与马克思主义的列宁主义之论战中考茨基对苏维埃制度的批评:没有人道的政治制度就没有社会主义国家,试图把这种制度建立在残忍横暴的基础上,这是最不好的。俄国的专政破坏了一切知识的自由,我们主张对我们西方说来是理所当然的自由,而反对俄国的专政。来自马克思主义内部对无产阶级专政的批评更切中要害。对于社会民主主义而言,保障自由的政治形式是也只能是议会共和国。

七十四

列宁对曾经的同志、同路人与同盟者孟什维克与社会革命党人更为苛酷。列宁的一位革命战友曾回忆革命前与列宁的一次对话:“我对他说:’弗拉基米尔-伊里奇,如果你夺取了政权,恐怕你在第二天就会动手绞死孟什维克。’他扫了我一眼回答道:’我们将在绞死最后一个社会革命党人之后绞死第一个孟什维克。’然后,他皱起眉头笑了笑”。十月政变夺权后,列宁授命捷尔任斯基创建的全俄肃反委员会主要是为了对付立宪民主党、孟什维克、左派社会革命党这些联合政权的同盟者。1919年2月捷尔任斯基即指令各省肃反委员会对左派社会革命党人和孟什维克进行“最严格的严视”。1921年苏维埃政权决定取缔一切非布尔什维克政党。1922年8月俄共(布)决定对社会革命党和孟什维克进行镇压。1923年2月国家政治保卫总局的秘密通令中,所有革命前政党的成员都是肉体消灭的对象。史载:“沙皇政权在1826年至1905年间处决的政治犯共有894名,但布尔什维克执政第一个月,死于政治原因的人达十万人。”列宁坚持肃反委员会式的专政是实现向社会主义的唯一道路。全俄各地有610个契卡工作委员会,1000多个革命法庭,1918-1922年被契卡杀害的人不少于200万。契卡在其成立后的十年间都是秘密机构,1927年才公开。沙皇的秘密警察队伍最多时一万五千人,契卡在三年间便有了25万正式工作人员。

七十五

列宁创建的领导世界革命的共产国际在第二次代表大会上制订了《二十一条》,要求对加入共产国际的各国党派团体进行清查,以防止“实际上还没有真正成为共产主义的”的党派团体加入共产主义,在各国工人党与工会中清除“改良主义者和中派分子”,以使各种领导机构都由“经过考验证明是忠实于无产阶级事业的可靠的共产党人”担任,接受共产国际的集中化的纪律。列宁在第三次共产国际代表大会上对意大利代表说:“立即从你们党内把改良主义者开除出去,工人群众会跟着我们走”。共产党的历史使命,用共产国际常用的军事术语讲,就是使国际无产阶级大军信仰共产国际的战略,从而把这支大军改造成为革命大军。《二十一条》分裂与削弱了世界的社会主义运动。共产国际所属各支部党员的人数也由1921年的887745人下降到1924年的648090人,到1928年又下降为445300人。

七十六

1921年以后,列宁托洛茨基预言的由俄国革命引起的欧洲革命并未爆发,共产国际命令全面退却。1925年国际社会党决议称:“共产国际幻想凭借百战百胜的红军的刺刀就可以实现工人的解放,认为为了完成世界革命必需进行新的世界战争。它支援亚洲和非洲的革命运动,并且希望依靠这种革命运动,用战争来给予资本主义以致命的打击”。欧洲革命与世界战争落空之后,列宁开始把目光转向东方,转向中国、印度这些人口众多的东方区域。列宁认为,世界革命需要一个新的序幕,即东方被压迫国家的资产阶级民主革命。1922年11月在最后一次出席的共产国际第四次代表大会上,列宁称决议完全是依据俄国条件写出的,他建议“要从头学起”,不要对共产国际纲领通过什么决议,而其逝后,正如马克思被变成“列宁式的马克思”一样,斯大林也把列宁变成“斯大林式的列宁。”

七十七

本来,列宁依照布尔什维克集中制原则打造的共产国际就是高度集权的,其执行委员会直接指挥各国支部,其决议各国支部必须不折不扣贯彻执行,如考茨基所述,一切社会主义政党,凡不接受新国际创始者的要求的,就一律排除出去。布尔什维克,在列宁的指挥下,就组成了这个新团体的核心。与第一国际和第二国际的民主结构相反,“第三国际或共产国际是严格地独裁的。第三国际在莫斯科建立了常设机关,完全成了俄国政府的工具。”而列宁逝世后,共产国际各国支部又开展了“布尔什维克化运动”。这就使它们更成为俄国政府的国外代表人,成为“莫斯科中心的盲目的工具”。从共产国际第二次代表大会到第六次代表大会,对章程的几次修改更加强了执行委员会的集中制权力。

七十八

以往对1917一1921年间苏维埃政权的研究较注重国内革命战争与对外战争,其实列宁在这一时期的战时共产主义政策与实验是最重要的内容,这就是“用无产阶级国家直接下命令的办法在一个小农国家里按共产主义原则来调整国家的产品生产和分配”。1920年10月列宁对共青团员们说:“现在15岁的这一代人,就能够看到共产主义社会,也要亲手建设这个社会。”因此,“现在是15岁,再过10-20年就会生活在共产主义社会里。”1921年2月曾是十月起义强力支持者的喀朗施塔得水兵发起反苏维埃权的暴动,喊出了“打倒布尔什维克暴政”、“没有共产党的苏维埃”、“自由苏维埃”的口号,破灭了列宁的共产主义梦想,经济崩溃、饥荒与暴动逼迫列宁不得不转向与资本主义做交易的新经济政策。

七十九

高尔基对十月政变与战时共产主义的尖锐批评在苏联被封存了七十年,这些当时在《新生活报》刊发的犀利评论后以《不合时宜的思想》在彼得格勒结集出版。1921年10月诗人古米廖夫被枪杀后,高尔基侨居欧洲十二年。翻阅高尔基的这些历史记录,倾听这位自学成才的文豪“在这些普遍兽性化的日子里变得更人道一些吧”的恳求,仍令叙史者难以自控心灵的激荡。高尔基抨击战时共产主义是“列宁在用工人的血、工人的皮做一场极端的兽性试验,列宁为了自己的试验让人民血流成河。”高尔基说,在十月政变中,“无产阶级既不宽容大量也不公正,它没有创造出任何有生命力的东西。布尔什维克断送了、掏空了、毁坏了祖国,把俄国作为一个疯狂的大试验场,把人民变成他们革命梦想的试验品。”高尔基伤感地重提了他曾诅咒的陀斯妥耶夫斯基的《群魔》,“革命痞子”出世了。他致信列宁称:“你们谩骂吧,但我就是如此思考的,我从不想把自己的思想变成你们主义的附庸。”

八十

共产国际来到世间,如《共产国际宣言》所称:“只要我们没有建立全世界的苏维埃联邦,我们国际无产阶级就决不会让刀剑入鞘……共产国际是国际无产阶级革命起义的党”。名副其实,共产国际有三座共产主义大学为世界共产主义革命培训干部。包括后来为中共培训干部的莫斯科中山大学。列宁在国内饥荒饿死千百万人的人相食时期,仅在1918-1921年间用于援外革命812232600金卢布。而1920年苏俄总共产出1亿5000万金卢布价值的商品,同期的农业产值是20倍多(只有战前的64%)。其中1921年,外援6200万马克的外汇宝石支持德国革命,宝石中有俄国末代皇后的珍珠项琏。1922年援助意大利共产党400万里拉,援助德国4700马克,援助法共64万法郎。

八十一

共产国际是列宁依照布尔什维克的“民主集中制”建立的。列宁的政党与领袖理论决定了共产党金字塔式的等级权力结构:最高领袖或某几个核心领导控制中央委员会,中央委员会控制全党各级组织与全体党员,而党又作为核心权力控制政府和社会组织,党也就成了列宁所要求的把最高领袖的指令从最高层传达到最基层的“传送带”。共产国际自1919年成立之日起,即要求所属各支部严格遵守这样的民主集中制:共产党必须建立在民主集中制的基础上。民主集中制的基本原则是:上级党组织要由下级党组织推选,而且上级党组织的所有指示都对下级党组织有绝对的和必然的约束力,必须有一个坚强的党中央,而且在两届党代表大会期间,党的所有领导同志都必须完全而且毫无疑问地承认党中央的权威。后来毛泽东的纪律是:下级服从上级,全党服从中央。

八十二

回顾1917年开端的从俄罗斯到中国的共产主义实践运动,可以发现其是两种人类思潮与实践的汇流,发源地不是巴黎公社,而是法国大革命后期的雅各宾恐怖统治,几乎现代以所有革命乌托邦裁决人类理想的源泉都从巴黎的断头台与咖啡馆奔涌而出。一是对现代社会的辩证法批判而产生的马克思主义独断体系,一是地下密谋的暴力革命传统,两者为共产主义革命的策略大师列宁的集中制军事化组织系统创造性结合,酿造成人类半个地球的共产主义政治经济与文化风暴,而他所创立的共产主义革命指挥中枢一一共产国际一一对各国人民的命运发生了重大的影响,共产主义的反思应始于列宁和列宁主义。反思二十世纪人类共产主义实践与理论的教训,才能充分认清阶级斗争与无产阶级专政施加于人类心灵与社会的无尽的创伤,也更能清醒地把握改良的渐进和平演化是人类变革的坦坦大道。

八十三

从古代的共产主义到中古以降的共产主义,以及当代共产主义,其共同的一点是将人类文明史的罪恶归因于私有制与私有财产,而认为共有制的合作方式为消除文明祸根的有效途径。从实践上,除了在宗教小团体与近代若干社会主义小社区的财产共有制实践有其优点之外,以国家权力推行的财产国家制仅仅是以一种政治特权阶层取代传统的有产阶层而已,并因国有财产的责任机制之缺乏而导致大量的浪费,全盘国有制的制度安排除了方便高度集中的政制中特权集团之外,对绝大多数民众仅仅是享有平等的贫困。列宁“战时共产主义”的四年实践与毛泽东十年文化大革命的实践是共产主义的典范。国有制下的人民并未分享文明的成果而是不断为政治斗争所困扰,共产主义承诺的美妙愿景注定是永远难以兑现的梦幻。财产不是公正之敌,而是人类自由幸福和谐的保证。

八十四

意识形态视角下的阶级与阶级斗争与现代社会学从实证观察研究的阶级与阶级斗争是不同的,前者的阶级与阶级斗争仅仅是社会革命运动的工具。马克思的阶级斗争学说取自法国大革命及法国王朝复辟时代历史学家对法国大革命的认识。依据马克思创立的唯物史观,阶级社会的存在是生产力不充分发展的历史阶段,这种观念赋予阶级某种历史的合理性,另外马克思认为现代阶级斗争必然导致以消灭阶级为目的的无产阶级专政,这种阶级斗争又是生产力全球化大发展的结果。马克思的所有革命预言都落空了。最文明的现代化国家并未发生无产阶级革命与无产阶级专政。如果说,无产阶级专政对马克思而言是现代经济危机引发的无产阶级阶级斗争的自然产物,那么,对列宁来说,无产阶级专政是革命政党创造出来的。既然如此,阶级斗争又为什么不能人为制造出来呢?毛泽东显然较其宗师列宁更具创造的天赋。

八十五

列宁-毛泽东的辩证法强调对立面的斗争。这是共产主义的哲学基础。我们人类所属的智力种群究竟以何种方式从东非的森林遍布地球繁衍至今的?据经验的观察,人类凭借竞争制度下的合作所创造的文明成果与文明进化远远超过破坏性的斗争。据我观察,有史以来人类三种大规模世界性斗争的极端形式一一种族(民族)斗争、阶级斗争、宗教斗争,给文明社会造成了最深重的灾难。相互仇恨与不容异见就是这三类斗争的遗产与根源。而文明的生活则以竞争制度的法治秩序为优胜,人权在法治下的成长是最适于人性的人道关怀。在经过千曲百折的迷途与探索之后,人类的自由终于不再是哲学必然性的抽象,而是个人实实在在的权利。常识胜于玄辨。

八十六

1917-1921年间,俄共内部在政策制定之前还是有相当活跃的自由讨论的。如1918年与德国签署布列斯特-里托夫斯克和约时期,但到1921年3月关于工会问题的公开论争后,俄共第十次党代表大会专门通过了《关于党的统一》的决议,其中规定:“责令立即毫无例外地解散一切不论按何种政纲组成的集团……禁止任何派别活动”,还规定“代表大会授权中央委员合,在遇到违反纪律、恢复或进行派别活动的情况发生时,可以采取党内一切处分办法,直至开除出党”。此决议一出,党内派別消失了,自由讨论也消失了。到斯大林时代,党内异议变成反党集团的证据。1923年斯大林在他主持的俄共(布)第十三次代表大会作报告时公布了当时是机密的《关于党的统一》决议关于取缔一切派别活动的第7条。列宁逝世后,斯大林讲列宁主义特别是无产阶级专政的理论和策略,党是无产阶级专政的工具,是“排斥任何派别活动和党内权力分散现象的”,是“靠清洗自己队伍中的机会主义分子而巩固起来的。”

八十七

在探索马克思对共产主义的论述与展望之前,先玩味检讨其对通过共产主义的过渡过段一一无产阶级专政或无产阶级独裁的推论。 无政府主义-共产主义者巴枯宁批评说:“马克思说,这个少数将由工人组成。是的,没错……是由先前的工人组成,但是他们很快就变成了人民的管理者或代表,而不再是工人,并且开始从国家权威的高度来向下俯视工人群众,所以他们不代表人民而只代表他们自己,代表他们自己对统治別人的要求权。谁要是怀疑这一点,只能说明他丝毫也不懂人性……他们(马克思主义者)声称,只有独裁(当然是他们自己的独裁)才能给人民带来自由。我们的回答是,独裁除了力图使它本身长久存在之外没有任何其他的目的,它除了使人民陷入奴役而依附于它以外,不会带来任何其他东西。自由只能通过自由来创造。”考茨基与德沃拉斯后来只是重复了巴枯宁的话。

八十八

共产主义曾经是一代人的旗帜,一代人的理想。当代共产主义的理论基础是马克思的学说。马克思对共产主义之构想迴异于魏特林卡贝巴枯宁之处,是他自以为运用科学的辩证法呈现了现代社会的自我否定。马克思以德国思辨学者的方式辛劳地蒐集了巨量材料论证了现代资本社会自我否定的运动直到炸裂,消亡,异化与阶级统治的消失,在历史的尽头,是马克思为人类设计的结束史前史的共产主义王国。共产主义是消灭了分工、交换与专业化的社会,劳动者摆脱了所有的限制而可以“全方位地发展他的全部能力,包括体力的和智力的能力,并将这些能力发挥到淋漓尽致的程度”。马克思写道:“在共产主义社会中,没有人再限于唯一的活动领域,每个人都能够完成他想要从事的任何活动。社会调节全部生产,因而使每个人今天做一件事情、明天做另一件事情成为可能,一个人可以早晨狩猎,下午捕鱼,晚上饲养牲畜,晚饭以后从事批评评论,就象我这样,拥有智慧,却没有专门成为猎人、漁夫、牧羊者或者批评家。”

八十九

马克思设想的共产主义时代的劳动者,是以审美的态度对待工作的艺术创造家,所有劳动都是艺术的,共产主义条件下的人已经从异化的人升华为审美的人,他以艺术的品味对待人与事。因为消除了分工,物品非常丰裕,可以实现个性的全面发展。托洛茨基说:“人将变成无与伦比地强壮、聪明、优美,他的身体更加和谐,他的运动更有韵律,他的声音更有音乐味道……人类平均将提高到亚里士多德的水平,歌德的水平,马克思的水平。在这些巨人之上将会出现新的巅峰。”那么,不通过分工、专业化与竞争性的市场制度如何创造丰裕的财富呢?恩格斯说:“禁止竞争按照它唯一可能的方式通过对价格施压來决定价值,只不过证明……一个人对于经济规律采取了通常的乌托邦式的蔑视态度”。恩格斯还称“如果竞争现在被禁止通过价格的升降来使单个的生产者知晓这些,那么世界的市场将如何存在,那时他们完全成为了瞎子”。商人工厂主的恩格斯把他的老伙伴划进了乌托邦的队伍。

九十

在沉思马克思关于共产主义纯粹审美时代的艺术畅想之余,我忽然想到尼采,想到了孤独的超人,考茨基讲在共产主义时“一种新型的人将出现……一种超人……一种升华了的人”,马克思设想的共产主义时代的新人是尼采的超人吗?惊人的会合,惊人的一致。尼采是倡审美代替宗教的先驱,他的阿波罗与狄俄尼索斯代表了人类的艺术理想。未来的畅想曲一一一位依据的是古希腊标准,一位自许为盗火的普洛米修斯。他们都深深根植于德国中古的神秘主义,都曾是浪漫派的弄潮儿,都反基督教的上帝,也都痛恨资本主义。一位创立了反现代的共产主义体系,一位创造了反现代的超人哲学,那么,从理想的殿堂到现实的人间,马克思与尼采究竟怎样影响了改变了人类的命运与心灵?

九十一

马克思运用唯物辩证法演示了人类历史在共产主义社会要达到其光辉顶点的必然性,同时,又以无产阶级先锋队的干预加速事件的进程,马克思称革命是新社会的助产婆。米塞斯评论:“如果马克思能够保持一致性,他就不应该从事任何政治活动。他将静静地等待“私人资本主义财产的丧钟敲响”的那一天的到来”。马克思不会静静地等待,他从青年时代起就是以破坏为己任的革命家。在大学时代致恋人燕妮的诗中,马克思写道:“……我将永远摧毀世界,因为我不想创造世界,因为他们从不听从我的召唤……”马克思迫不及待要“自觉参与社会的历史革命过程”,亲自敲响现代社会的丧钟:“那时我将能够耀武扬威地前进,像神一样踏过他们王国废墟的遗痕。我的每一句话都在燃烧和战斗,我的胸怀等同于那造物主的胸襟。”

九十二

人与神合一在黑格尔是达到绝对理性,不是上帝转成耶稣转成人身,而是耶稣变成上帝变成神。黑格尔的神学辩证法被马克思改造成无神化的历史唯物主义,以异化或后来阶级统治的掘墓者一一无产阶级消灭哲学而实现哲学。对马克思而言,人类的罪孽甚至不能归咎于阶级与阶级剥削,因为后者也不过是人类之分化一一分工、交换与专业化的产物,是历史的工具。资本社会及其世界市场把这种分化达到极端,达到富有与贫困的两极,从而也使其山穷水尽,无产阶级革命与无产阶级专政既消灭了自身也消灭了分化,人类重新合而为一。“否定之否定”的辩证法一一共产主义的神学法则高奏凯歌。波普尔说:“哲学家总是要让他们的周围笼罩着某些神秘的气氛。哲学被认为是一种奇怪的和深奥的东西,它要处理那些宗教要去处理的事情……它被认为是知识分子、有学问的和聪明的人的宗教和神学”。谁会猜想唯物主义的辩证体系里潜伏的一套苦心构建的救世神学呢?

七十三

从列宁回到马克思,从马克思回到黑格尔,回到德国十九世纪思辩哲学,就可以发现七十年来大陆知识界对西方世界与西方知识及宗教的整体世界观,在一些最基本的观念上与从苏格拉底到哈耶克的西方主流知识体系的误差,不消除这种意识形态造就的这种误差、隔绝与鸿沟,我们就无法从共产主义体系进入对现代文明的理解,就无法把握现代文明之精神与信仰的根基。比如,黑格尔体系中的自由概念从其严格意义上说是集权。或如黑格尔语言称把自身作为“一个自我充分理解的整体,即消除人们异化与有限性的悲哀。这与法权下的“自由”意义风马牛不相及。又如黑格尔把“国家”当做一个有机体并为其自己的目的而存在,把“国家”神化为当代世界中的精神及“天堂王国的现实”,更是无助于对现实国家的认识。

九十四

共产主义的秘密不在马克思的政治经济学与人类学中,而在其哲学,在其十九世纪四十年代哲学手稿的“异化”中。马克思在黑格尔的辩证法里领悟了炸毁现代市民社会的否定原理,又从法国大革命的恐怖时期发现了否定的关键力量一一革命的无产阶级。革命的泛政治化力量将在摧毁多样化的市民社会时使社会充分集体化,人类将作为一个完整的“物种存在”,马克思在1856年的一次演说中讲到德国中世纪的菲默法庭,他说“:如果一幢房子画上了一个红十字,那么人们就知道它的所有者受到了菲默法庭的判决。欧洲的所有房子现在都画上了神秘的红十字。历史就是审判官,而它的执行人就是无产阶级”。马克思的全部政治经济学,无产阶级的圣經一一《资本论》,是为共产主义的选民进行历史与道德论证,以使它们自觉为共产主义政治宗教的革命先知与使徒。

九十五

马克思初出道山的两篇短论一一《黑格尔法哲学批判》导言与关于费尔巴哈的提纲一一已经概述了其学说的要旨。后者讲哲学的要义仅仅是实践改造世界的目标……而前者,则宣称无产阶级以革命实现人的最高本质从而“宣告现存世界制度的解体”,也就是把哲学变成现实。奇诡的是,恩格斯整理出版的《资本论》第三卷即终卷,马克思写到“阶级”就结尾了(恩格斯脚注:手稿在这里中断了),戏唱到终场没有观赏高潮,不免有些遗憾。叹息之余,马克思笔及“发展程度最高和最典型”的英格兰,无意识地信笔由心:“中间或中等的社会阶层,[它]在这里甚至淹没了所有的分界线”……非同小可,伯恩斯坦正是从这个缺口修正了并最终炸毁了马克思的共产主义革命救世体系,而将社会主义引向了改良现代制度的社会民主主义。也只有在社会民主主义开拓的现代福利社会的先贤祠里,马克思才能享有一个光荣的位置。’

九十六

据恩格斯回忆,马克思走的很安祥。静静地睡着了。而列宁死前仍在博斗,他要与托洛茨斯联手扼制斯大林与捷尔任斯基的大俄罗斯主义以捍卫格鲁吉亚的民族自决权,他要改组工农检察院监督官僚主义,他要撤换“太粗暴”的斯大林总书记的职位……他无能为力了,他似乎被他一手打造的苏维埃专政“利维坦”惊住了,但他也被控制,被斯大林监控,因为他中风了,患了失语症,“他的全部词汇只有几个词”。为了治病,必须停止工作。组织背后的个人权力有多专横,他自己也体会了,感受了。在他发表的最后几篇文章中,讲到中国,讲到“斗争的结局归根到底取决于如下这一点:俄国、印度、中国等等构成世界人口的绝大多数。……非常迅速地卷入了争取自身解放的斗争……在这个意义上说,社会主义的最终胜利是完全和绝对有保证的”。恩格斯说,燕妮死时,马克思就死了。知情者说,听到情人伊涅萨的死讯,加速了列宁的死亡。

暴力革命曾被马克思赋予神奇的力量将最被异化的粗鄙的无产阶级改造为共产主义的新人,而于革命内战中成就的“革命者种族”却是“持久地、残忍地失去清白”,列宁的战时共产主义是俄罗斯历史上最悲惨的世界,军队与契卡主宰了人民的命运与生活,恐怖成为一种国家政策,十月起义的主力被迫发动反布尔什维克的喀琅施塔得叛乱并被残酷镇压,幸赖休生养息的八年新经济政策(l921一1929),苏维埃政权才度过危险。十月政变以后,列宁心仪的涅恰耶夫被称道为“有着火焰般激情和非凡的气魄的革命者”,是俄国革命初期“唯一的阶级斗争的榜样”,其“超越道德束缚的政治行动理念”为列宁发扬光大,列宁在1920年教导共青团员们道德“完全服从于无产阶级阶级斗争的利益”,而斯大林始终在研究涅恰耶夫,三十年代初,他又全部调阅了涅恰耶夫的材料,就在大肃反的前几年。

九十七

暴力革命曾被马克思赋予神奇的力量可将最被异化的粗鄙的无产阶级改造为共产主义的新人,而于革命内战中历练的“革命者种族”却是“持久地、残忍地失去清白”,列宁的战时共产主义是俄罗斯历史上最悲惨的世界,军队与契卡主宰了人民的命运与生活,恐怖成为一种国家政策,十月起义的主力红水兵被迫发动反布尔什维克的喀琅施塔得叛乱并被残酷镇压,幸赖休生养息的八年新经济政策(l921一1929),苏维埃政权才度过危险。十月政变以后,列宁心仪的“布尔什维克久远的先驱”涅恰耶夫被称道为“有着火焰般激情和非凡的气魄的革命者”,是俄国革命初期“唯一的阶级斗争的榜样”,其“超越道德束缚的政治行动理念”为列宁发扬光大,列宁在1920年教诲共青团员们说,道德“完全服从于无产阶级阶级斗争的利益”,而斯大林始终在研究涅恰耶夫,三十年代初,他又全部调阅了涅恰耶夫的材料,就在大肃反的前几年。

九十八

从俄罗斯大地上成熟的涅恰耶夫-列宁-斯大林队伍将走遍天涯海角,其培育壮大的“革命者种族”将在亚非拉广阔天地翻江倒海,因为共产国际将把重心转向东方并以布尔什维克原则打造各国共产党支部,共产国际主席季诺维也夫称“除了列宁主义,就不可能有革命的马克思主义”,列宁关闭了与社会民主主义-自由主义的对话合作,对于任何政治异议贴以污辱性的标签肆意攻击。从共产国际第二次代表大会到第六次代表大会,几次对章程加以修改,执行委员会之权力越来越大,1924年共产国际五大强调执委会的指示是命令,“必须执行”,执委会有权“撤消或修改各支部中央机关和代表大会的决议,并作出各该中央机关必须遵守的决议”。1928年共产国际设立西欧局、南部非洲局、东方局等机构以加强控制。恰如考茨基所言:“各国共产党只是它的训练有素的地方卫士。俄国现时统治者的共产主义已经成了沙皇的泛斯拉夫主义,所不同的是今天的共产党员对于独裁者,比泛斯拉夫主义者对于沙皇还更恭顺得多罢了”。

九十九

二十七前一埸夭折的民主抗议,或许是中国一百年革命最后的回响。枪声过后,大洋彼岸传来“告别革命”的反思。而开启现代革命的法国大革命,却吸收的是美国革命的灵感。对于跨洋而来的自由女神,美国开国者是以哀痛的思绪对法国人说,“要想自由能在旧世界生根,不得不先付出血流成河的代价”。合众国驻法大使杰斐逊直陈任何自由为“欧洲城市的暴民”所拥有,“都会瞬间扭曲为对一切私人的和公共事物的破坏和毁灭”。何况沙俄压迫下的臣民呢?法国大革命掀起的滔天巨浪将革命圣化为图腾,以德国辩证法的神威横行天下,其所呼啸而出的新型革命者“为了能够实现心中的某种理想目标,竟不知任何动摇和怀疑”,他们“从那一特定历史时刻诞生之日起,就培育了整个他们自己的种族,这一特殊的种族将在文明世界的各个领域里迅速地繁衍、壮大。无论在哪里,他们将保持着同样的面貌和同样的特性。我们知道这一种族的萌芽状态,而至今,它仍旧活跃在我们的眼前”。

革命,真的可以告別吗?


陈坡:文化大革命沉思录

$
0
0

陈坡:文化大革命沉思录(一)

当代中国起源于文革,当代中国的大部分问题亦起源于文革,中国人的文革情结与希伯来人的该隐情结一样,考验着国人的道德智慧。如此巨大的苦难与浩劫,是一个巨大的存在。心在,人在,信史亦会在。

【作者简介】:陈坡,党史专家,1982届北京大学中共党史研究生,法学硕士。现任北京大学历史文化资源研究所副所长。参与主编《文化大革命辞典》、《共和国重大决策内幕》(四卷八册》、《告別乌托邦》(上、下)。
写在《文化大革命沉思录》前面的话

文革的五十年,对于中国人,是特別的年份,特别难忘的岁月。五十知天命,五十年后知文革吗?国内刊行了几部文革史,王年一《大动乱的年代》仍是独到的一部。与梯也尔那样的法国大革命史和麦考莱那样的英国革命史同等规模与水平的文革史,尚待时日。官方,一如既往是遗忘,似乎十年不曾存在。未销毁的档案密封在戒备森严的库房里。民间对文革的兴趣与日俱增,口述史方兴未艾。而科学的研究则是期待。现实的烦恼与惶恐,也许是人们的过虑。我不认为文革有复辟的可能。虽然时常看到听到黑格尔有关重大历史事件经常发生两次的警示,但文革是一去不复返了。神州已无毛泽东。副帅讲,五百年出一个。五百年或太长,五十年又太短。二十年来,为毛封神的势力与努力一直存在。海内外的舞文弄墨者编造了比毛生前更多的毛{的}神话。毛恐怕比任何一个历史人物都失去其本来面目而面目全非了。如果我们这个有悠久史学传统的文明古族还可以复兴为有创造力的现代民族,参与现代文明的建设,那么,就一定不会忘记文革与文革的教训。当代中国起源于文革,当代中国的大部分问题亦起源于文革,中国人的文革情结与希伯来人的该隐情结一样,考验着国人的道德智慧。如此巨大的苦难与浩劫,是一个巨大的存在。心在,人在,信史亦会在。

(草于2016年3月25日 陈坡)

文化大革命沉思之一

文革如戏,有序幕,有高潮, 有转折,有”神界的黄昏”,有尾声。但丁《神曲》的地狱、炼狱与天堂艺术地再现了文革的三个阶段。文革是神曲吗?是神的颂歌还是神的葬礼进行曲?什么是文革的主旋律? 什么是文化大革命的”根本精神”?这是反思文革碰到的首要问题。文革的性质当然不是什么反修防修,更不应从发动者的主观意图中去判断。从六十年代中期的困境看,大饥荒恢复时期的中国迫切需要一个既恢复经济也恢复人性与人道的修正主义阶段(无论是赫鲁晓夫-勃列日涅夫式的修正主义,还是东欧式的修正主义以及欧洲的社会民主主义,都是纠正与缓和激进的阶级革命之消极后果的有益尝试)……文革显然是与休养生息的现实需要背道而弛的,是悖道之举,那么,这个逆举的风暴起于坚守列宁原教旨的”伟大领袖”,虽然文革的发动者承诺一场灵魂深处的革命,纲领是斗私批修,试图以强制改造人性,是登峰造极的妄举。胡乔木说:世界观怎么能革命?革命怎么能解决世界观问题? 修正主义被咒为罪恶之源,而文革的根本精神却首先是把这个偏执的伟大领袖塑造成亿万愚众的偶像,占据神圣性之缺位,以其”乾纲独断”导演一场毁灭文化文明人性与社会的荒唐戏剧。

文化大革命沉思之二

以必然论阐述文革起源的理论模式应警惕陷入宿命论的观念陷阱,犹如对文革机制的制度性深层解析不能冲淡对个人责任的探究。勒庞讲得好,研究历史,应当极为警惕在宿命论掩盖下的无知。以史为鉴是中国的史学传统,但吸取历史教训为什么难上加难?在人的观念、知识结构与社会政治环境未有实质性的改进时,历史不是创新,而是循环。文革虽然过去四十年了,对文革的认知有多少进步?对文革究竟有多少反思反省?研究文革,有多种视角,从下到上,从基层到中层,从上到下,从首都到地方,从城市到农村到边疆,从国内到国际,从现在到过去,各有各的观察与判断……但文革毕竟是中央号召的,毛决策的,不是什么天然的群众运动,政治史,是文革的核心部分,是纲。因此,文革起源的谜底必须回答以下问题:毛为什么发动文革?毛为什么能够发动文革?毛如何发动文革?文革的真实目的究竟是什么?毛对文革起因的论述前后是否一致?其中前三个问题的探寻必须追溯中国共产党的全部历史与理论,尤其是延安时期以后领导集团的分化组合,比如毛的神话是四十年代与六十年代两次造神运动的结晶,还要探索中苏关系之演变与国际共运的轨迹。因为国际反修与国内反修是恶性的互动。

文化大革命沉思之三

个人崇拜是文革的突出现象,其规模与信众应为史无前例,亦是文革之祸因。怀疑一切的文革只有毛和毛思想不能怀疑、不准怀疑、禁止怀疑的。文革法是《公安六条》。毛是真理的化身,代表真理的领袖,片言只语皆是最高指示。个人崇拜即偶像崇拜,对领袖的偶像崇拜与盲目信仰。在无神论的国度、地区与文明,是否必然发生偶像崇拜,值得研究。历史经验证明,无神论的文化土质与心理结构容易滋生偶像崇拜的奇观。而六、七十年代举国上下走火入魔的崇拜狂潮,有其强力的政治推动,有其历史的前因后果,是封闭社会的特有现象。在文革结束时通称为个人崇拜,或因袭赫鲁晓夫在苏共二十大反斯大林秘密报告的说法,亦称个人迷信。个人迷信更为准确。个人崇拜与迷信在共产国际与中共都有久远的历史。胡乔木曾说过,毛泽东是中国的斯大林,毛泽东也自认为是斯大林。所以,不仅应梳理解析延安至文革刘、彭、林、周鼓吹领袖崇拜编织领袖神话的历史,也要探明毛泽东崇拜毛主席的自弹自唱。毛从中共八大以后发明”两种崇拜”的诡辩到主张所谓正确的个人崇拜,鼓励党内外对他本人的崇拜,实为有意识地为其政治上的个人独断取得正当性。

文化大革命沉思之四

什么是文革?这是文革的算术题,也是文革的代数题。作为文革中隶属于单位共同体而为户籍束缚无力逃脱的中国人,几乎都被动员而自愿不自愿地卷进了这场突如其来的政治风暴,时而叱咤风云时而身陷囹圄,造反、保守、逍遥,经受无常命运的起伏与感受人世炎凉的沧桑。每个亲历文革十年的人都有一部自己的文革史,也有一部自己的文革图像。只要诚实地面对自我,谁也不能不拷问文革。不知为什么,胡风那有点拗口的名句”精神奴役的创伤”时时想起,余味无尽。精神被奴役后留下的深深的伤痕,曾以”伤痕文学”记录一代人沉痛的心灵历程。经历了,并不意味着理解。我以为应以人道主义的宽阔视野研究反人道主义的文革,文革的存在状态:恐惧,政治恐怖,物质与精神的全面匮乏,意识形态疯狂,不是正常的心智所能参透的。那么,文革究竟是什么?谁的文革?两个文革还是一个文革?民众究竟从文革中得到了什么?失去了什么?三年还是十年?文革是历史、文化与语言的断裂,偶然意志的促弄,左派之间的内哄,还是社会主义-共产主义政治实践史的必然?绘制怎样的一画文革图像才能更理性更完整地把握文革的现实?文革,结束了吗?

文化大革命沉思之五

对于文革的后果、后遗症及对中国政治与社会的长远影响,绝不能低估。估为文革残余是轻敌。毛的遗体展示在首都的广场上,其”反资反修”的魔咒活在国人的神经中。毛左,活跃在大街小巷,招摇过市。文革,亦被文革理论家巧伪包装。最悲哀的是,我们都从毛时代走过,曾是毛左、毛分子,红小兵,红卫兵,有毛思想的遗因,同一物种……韶山,会是毛崇拜者的圣地吗?领袖崇拜会死灰复燃?万物有灵论的原始巫教的崇拜中心是太阳,难道神洲还会升起人样的太阳吗?从文革到改革,改革的背景是经济的凋敝、社会的碎裂与文化的废墟……文革既连根铲除了传统文化,又根本摧毁了神圣性根基。这是真正的虚无主义。去神性化与去人性化是文革与文革精神的主要特征。民国消失在遥远的过去。反思文革的两个维度一一精神与理性,是人之为人不可或缺的,是首先应确立的”理论良心”。无神圣性的根基,精神落叶无根,百孔千疮的人心难以自安,而无科学的分析逻辑,就不存在理性的条件。”然则吾人,其亦沉思而已夫,其亦惟沉思而已夫!”

文化大革命沉思之六

59-62年是中共建政史上最关键性的三年,因为这三年的旷世灾难一一”粮食关”一一古今罕有,不仅是中共建政以来经济赶超战略与举措的重大挫折,而且是以运动治国施政的大失败,对共产党人的理想信念与良知底线也是一个极大的拷问与考验,与毛在58年豪情万丈的向全球宣战相比,因饥饿而死亡的3000一4000万生灵煎熬着现实的人间,断粮的恐惧时时刻刻日日夜夜折磨着国务院,甚至应该说,47年内战以来一系列凯旋式胜利在大饥荒中化为尘埃……谁应负责?”人相食,要上书的”。自命为解放全人类的革命家怎样对待自己犯下的弥天大错?而自延安时期形成的中共核心层的分裂亦在此时,在一系列内政外交领域,八大以来确立的毛刘周朱陈林邓及两彭都发生了政治裂痕,其中包括政策分歧、形势判断、意识形态地位、对外方针、权力较量与责任归属…………这些难以调和的争议与猜忌共同把中国推向了难以逆转的文革,一场五千年难遇的浩劫,而其主谋者是毛。领袖核心的集中制制度为毛提供了独断的条件。”独裁好”。臥榻之上,岂容他人鼾睡,两个主席并立的局面摇摇欲坠,其问题仅仅在于,毛心目的中国赫鲁晓夫是何时并因何而成形的。这可是文革的头号敌人,革命的主要对象。

文化大革命沉思之七

虽然我倾向于把文革的爆发溯自62年以后高层分歧的逐步激化,但仍同意陆定一的判断,57年是转折点。因为在我看来,经典的社会主义革命实践在56年宣告终结,所有制关系决定的阶级基本消亡,党国单位为社会成员的栖存地。而57年反右后,改变了八大的基本判断,提出”资产阶级知识分子”与”政治上思想上的剥削阶级”的新概念,康生后来解释说,毛看阶级问题,不仅从经济范畴来看,而且从政治范畴、思想范畴来看。这为阶级斗争无中生有与扩大化的理论根据。59一62年关于大跃进与调整政策的党内分歧发生后,毛把这种阶级斗争观念延伸到党内,发挥了阶级解释的随意性,与国内外所谓复辟与颠覆势力联系到一起,阶级斗争是毛终生奉行的法宝,直至到毛决定对党政军进行大清洗,到文革后期,毛总结出党内资产阶级的新概念,做为社会主义革命的长期对象,而在社会生活领域,把阶级斗争转化为集体主义与个人利益之争,从而排斥任何成员的物质利益欲求,权力特权为主要的甚至唯一的私欲餍足方式。权力政治的极端形态披着阶级意识形态的外衣覆盖了山河大地。因此,发生了冯友兰评定的毛在思想史上的与政治实践上的荒唐阶段。

文化大革命沉思之八

59年的庐山会议是毛建政以来遭遇的第一次滑铁庐,并不是说毛的政治权威受到削弱,而是彭德怀的”意见书”对其心理上的巨大冲击。毛对”小资产阶级狂热性”批评的高度敏感显然是忆起了其在三十年代与四十年代缠斗不休的”王明路线”,不能完全排除彭以其道还治其人迫毛反省改错的暗讽,毛知道自己心亏,理亏,但认错改错却不是他的品性,毛是从不下罪己诏的。毛高踞政治局之上,我行我素。毛的反应是从反左到反右的大逆转,把58年开展的反右倾斗争进行到底,并排兵布将发动了对彭的全面清算。毛彭的决裂对中共的震动远远超过高饶事件。刘周林配合了毛对彭的清算,彭受到了党内同志的轮番围攻,软硬逼迫,不得不违心检讨,顾全毛的体面,因而中国人民注定要为毛的权威、空想与虚荣献上更多的生命更重的祭品。但耐人寻味的是,刘在会议后期要胡乔木转告毛勿将反右的中央决议传至县团以下,另外发一个反左的文件,以继续纠正泛滥成灾的共产风浮夸风,鉴于当时的政治气氛,胡未敢起草文件也未敢告毛。后来胡受到刘的责问后,竟以养病为名退出了中枢……毛刘的蜜月接近尾声。

文化大革命沉思之九

大跃进的惨重失败及给农民造成的巨大苦难,在当时就引起了党内外有识之士的批评议论,其反映在更真实全面掌握信息的中共高层,也发生了种种或明或暗的不同意见,我不想在这篇概述性的文革史导论中旁征博引,史料俱在,千古不磨。陈云、邓子恢在农村调整政策(三自一包)与毛的分歧(陈向毛建议分田到户),周恩来陈毅在知识分子性质上与毛的分歧,邓小平在平反右倾上的一风吹做法(平反300万),朱德对公共食堂的尖锐批评和单干的主张,彭真对大跃进文件的清理并点名要毛检讨错误并承担责任,陈甚至讲集体化以后再搞……最重要的,是自称”非常时期大总统”的一线领导人刘少奇对形势、政策与三面红旗的评价,他在湖南调查时说大饥荒时期死的人比秦始皇和隋炀帝时还多,其主因是人祸,他主张”退够”。刘在起草七千人大会报告时,提出对四年失误要讲透,有多少讲多少,中央负主要负责,失误原因与党内过火斗争特别是庐山会议只反右不反左及会后在党内普遍进行反右倾斗争有关,党内民主不够,使许多错误不能及时改正,重病要用猛药。这些核心领导层的意见尤其刘的主张都深深刺痛了自负自恋自我崇拜的毛。他在战友们心目中百战百胜的光辉形象蒙上了阴影,对其建设能力的怀疑在高层滋生,因此可以认为,毛的赫鲁晓夫情结与心病就是六十年代初形成的。

文化大革命沉思之十

毛的政治生涯有三个重要阶段,夺权时期,大跃进时期,文革时期。毛临终回首只讲了两个时期,夺权与文革。把文革视为生平创举,而迴避了毛进行超英赶美的经济大跃进与共产主义实验而导致四年大饥荒的极其重要的历史,为什么呢?(1)毛的幸与不幸都在于其头脑始终是清醒的,刻意遮沒的往往是念兹在兹的,他的恶梦是遍野饥号的大饥荒而非文革,反官僚反修大民主的青春白日梦老少皆宜,轰轰烈烈,享足了天下大乱到天下大治的后现代虚拟现实的况味,把二十年代兴起的左翼共产主义运动推向了闹剧式的高峰,毛把七千人当做牺牲品抛给了受其迷惑的暴民,而五十年代末六十年代初旷野的哀音却不会湮没的。大跃进从农业生产跃进肇始,以农民受难终结。文革亦以学生造反爆发,以上山下乡冷却。(2)40后50后的中国人,最刻骨铬心的未必是文革的闹剧,而是饥饿,大饥荒。是少年童年时代的粮食关。饥饿与饥渴症是这两代人成长的真正烦恼。而所谓三年自然灾害是弥天大谎,是第一面神秘的面纱。而第二面面纱是文革织就的,因为里面有文革起源的全部密码。青少年的狂热犯罪可以压抑童年的匮乏,奉旨造反释放了青春期受压抑的冲动。(3)研究者与观察者可以把党内冲突远溯到二三十年代血腥肃反的苏维埃时期,也可以驻足于红太阳升起的延安,但对于文革,对于四十年代开始的毛刘联盟到六十年代中期破裂的文革,其主要成因却不必追溯那么远,因从庐山会议(59年)到庐山会议(70年)的政治轨迹足以见证文革的酝酿、发动与运行,对毛思想的复杂性与单一性可作多视角的分析,尤其要联系其政治实践。千秋始皇谁欲求,毛刘?唯见红墙起洪流。(4)因此看来,最被掩饰的历史一一刘少奇曾称”活人不揭,死后下一代揭”的大饥荒是文革的发源地。而1962年的七千人(大饥荒的主要责任群)大会,对中国共产党人尤其是高层领导人,是一次底线良知的测验。检讨和批评大跃进是从这个大会开始的。毛刘分歧也是由此扩大的。江青68年讲,这次革命应该追溯到八届十中全会,就是1962年,我们伟大领袖在那个会上就提出了阶级、阶级矛盾、阶级斗争这个问题。为什么提出呢?就是有人反对毛主席的无产阶级革命路线(群众高呼:打倒刘少奇!)。 而文革的真实目的却是,以反官僚主义的群众造反永远地埋葬这个秘密。从这个意义上说,文革似乎胜利了。因为参与文革的一代青少年将有一个光荣的青春回忆与革命回忆,反官僚永远是正确的。

文化大革命沉思之十一

如果说,58年莫斯科会议后毛雄心勃勃与赫鲁晓夫争锋国际共运的领袖,以超英赶美的人定胜天之豪气闯下了饿殍千里的滔天大祸,59年败象尽露后仍坚持乌托邦实验与跃进指标,到61年面临崩溃,不得不实行调整政策,苦渡困厄,那么,熟读帝王史书而精明透顶的毛此时此刻所考虑的就是死后声名的身后事了。赫鲁晓夫清算斯大林的秘密报告越来越成为他念念不忘的心病。所以,毛的选择不是改弦更张,而是以挑起意识形态谬误争论转移目标,重新祭起阶级斗争的旗帜,在北戴河会议高谈阔论形势与阶级斗争,批判所谓黑暗风、单干风,翻案风,利用一本所谓为高岗翻案的小说,制造了习贾刘反党集团,通过意识形态领域夺占先机而卷土重来,对一线主持的经济恢复工作进行制约,而林彪主导的军队,以”政治挂帅”导演了在全国全党范围内对毛的造神运动。军队、政党与人民的政治指导思想逐渐为立竿见影的”毛主席语录”所支配。个人崇拜强化了毛的政治地位。军队在国家政治生活的作用更为突出,由训政时期到军政时期的过渡亦开先河。

文化大革命沉思之十二

内政决定外交,内政决定社会主义国家间政党关系。大跃进失败后的政治斗争加剧了中苏两党两国关系的恶化,这个政治的主旨就是在国际范围内坚持反美的革命,在国内坚持清肃异己异议的”阶级斗争”,而苏联苏共的最大罪状是与美国”和平共处”、”和平竞赛”,支持欧洲社会主义”和平过渡”,并自称为”全民党”、”全民国家”,这是62年以后毛从国际反美转向反美反苏的根本原因(赫鲁晓夫对大跃进的尖锐批评也是触怒毛的重要因素),同时又借势把这种激进好战的反苏反修转向国内党内,制造紧张气氛,如给对大跃进有意见的国防部长彭德怀构陷了”里通外国”的罪状以置之死地令彭死不暝目。所谓中苏大论战,虽有邓小平后来所谓民族”受屈辱”之曲辩,实质是服务服从于国内党内的毛式阶级斗争政治的需要,以坚持列宁原教旨应对国际和平、变革与科学发展的变局,固步自封,饰非拒谏,以遮蔽内政失误转移危机并压制正常的批评异议,是一种愚臣愚民手段。反修反帝使中国的国际地位更加孤立。

文化大革命沉思之十三

托毛之赐,中国人几乎无人不知苏共领袖赫鲁晓夫,但又有几人真识这位矿工之子呢?赫氏作为退休者临终曾经忏悔:”我的双手沾满了血腥,这是我内心感到最可怕的事情”。但赫氏无负于中国,反而有功,沙俄从中国东北掠取的权益是赫氏时代归还的,对华工业与军事的大规模援助是赫氏完成的,大饥荒时期又是赫氏主动提出对华援助粮食与糖,延缓偿债……但毛对赫的善举不屑一顾,以赫为国际头号大敌,主要是因为赫以”秘密报告”的方式在苏共二十大清算了暴君斯大林,开启了国际共产主义运动的第一次思想解放,戳中了毛继承斯大林的中国梦,对毛来说,反对斯大林就是反对马克思列宁主义。这份名为《关于个人崇拜及其后果》的报告对中共的冲击亦不可低估。刘认为应译为”个人迷信”。两卷《斯大林批判文集》证明赫氏报告的国际影响。中国”右派”的某些思想资源亦出自赫氏的报告。赫还是社会主义阵营的改革家,在内外政策上都做了一系列改变列一斯原教旨主义的举措,主张裁军,限制核武,与西方阵营和平共处、和平竞赛与和平过渡,不仅如此,赫氏对斯大林的挖尸焚灰也刺痛了毛,更让心高气傲的毛难以容忍的,是赫对大跃进的抨击并批评中国不具备共产主义的物质条件与政治条件。这是毛的麦城。58年与赫开始决裂,62年以后组织对苏共的九评,项庄舞剑,意在沛公,明指赫鲁晓夫与铁托,剑指中国的赫鲁晓夫。赫是毛的恶梦。毛至死未忘土豆烧牛肉。

文化大革命沉思之十四

那么,谁是中国的赫鲁晓夫呢? 无可讳言,文革的直接目标是推翻刘邓彭贺罗主持的中央一线领导,刘是文革打倒的首要对象。因此,不探究详查毛刘从合作、结盟到分歧、对立、决裂的全过程,就无法把握文革的起因。而不洞察毛何以利用以破坏为目的的学生运动群众运动和全面夺权的方式即”全面内战”(全国的全面的阶级斗争)摧垮从中央到地方的党政权力集团,而不是像对高岗彭德怀那样通过党内整肃予以罢黜,就不能深刻地认识文革的特殊性以及文革的消极后果。因为文革是领袖独断与群氓暴政的大动乱,是人类政治史上两种最坏的奴役形态的结合,亿万不明真相的群众被愚弄参与秘密政治的高层政争,打断了国家正常进化的过程,为祸甚巨,为害甚深,对几代人都是难以解脱的精神创伤。高层权争政争以全社会长期动荡内乱为代价,以亿万家庭生离死別的沧桑巨变结束,史无前例,也可能后无来者。文革的群众性是其反思的难点。然而,不摆脱文革的魔咒,不认清文革的真相,不否定文革的本质,不真正反思文革,不吸取文革教训,中国就永远无法进入现代文明。

文化大革命反思之十五

中共建政以后毛刘的意见分歧主要有三次,一次是五十年代初的新民主主义社会之争,其结果是53年过渡时期总路线与高饶事件。一次是56年冒进与反冒进之争,其结果是58年南宁会议与大跃进。一次是62年七千人大会及前后对经济形势与困难原因之争。其结果是调整政策、经济复苏和文革。毛刘分歧公开显露于65年社教运动的一次对话,这个运动局部试点于62年下半年,是毛布置阶级斗争的产物。对大面积饥荒与非正常死人的反应,如震惊朝野的信阳事件,毛认为是地富反坏右及党内坏人捣乱破坏,因而要求民主革命补课。其后果是更大的灾荒与人禍。经济调整政策的逐渐生效,毛认为动摇了农村集体经济的基础与三面红旗的正确性,62到65年,毛有计划地布署从基层到高层以及从国际到国内的所谓阶级斗争,以收回一线中央的权力,回到前台。文革之前,公安部明文规定的阶级敌人即所谓五类分子地富反坏右多达三千万人,株连亲属多达亿人以上。刘应对毛式阶级进攻战略的方法,是将斗争的锋芒引向基层干部的四不清,引向文化领域与传统的革命对象,这是毛刘分歧的政治背景,而自64年开始,毛已从大饥荒的消沉中振起,以政治策略家的机谋实施剪除刘邓中央一线的一系列政治设计……

文化大革命沉思之十六

对于六十岁以上的中国人来说,饥饿是六十年代前五年的记忆符号,革命与阶级斗争则是从六十年代到七十年代十五年间的记忆符号。饥饿的肚肠与为意识形态虚假叙事充塞的大脑是这个历史岁月的人的特有画像。无论多少妙笔,多神画技,也绘制不出另类的图像。人性的丰富,人格的尊严,个人权利的意识,人文的烂漫,遥不可及,消失于革命大批判的空洞文字。研究指导文革的思想理论,是一件枯燥且劳而无功的苦差事。文革的反动,不仅是共产主义乌托邦的幻灭,而是国民心理对文革理论一一阶级与专政一一的永久的厌倦与厌弃。但对文革的历程,亿万人的生命处境与磨难,存在的荒谬与蒙昧,青春的暴力与压抑,却应以人性、人权、人文的视角宜细不宜粗地反复考量,它离开文明究竟有多远?!《苦恋》结尾的人字问号意味深长,“什么是人?什么是人的存在?”文革,使亿万人难以进化为现代人。所有文革的亲历者,心里都有一本帐,一杆枰,都有权独立运用自己的理性审视与审判文革。

文化大革命沉思之十七

毛是从文武两条战线进袭一线中央的。对毛来说,根本问题是政权问题,“忘记了政权,就是忘记了政治。”枪杆子是政权的根本,枪杆子亦是文革的支柱。64-65年,毛决定在中直机关、国务院各部委成立政治部,其主要负责人由军队派任。在毛看来,当时形成了刘邓彭掌控的党机器与刘贺罗掌控的军事机器,而罗是兼跨党政军的实权人物。罗对刘贺的效从和刘对罗的信用是文革发动的绊脚石,亦是文革的隐患。65年底神秘的上海会议以“野心家”(“篡军反党”)和反对“突出政治”的罪名罢黜了茫然不知所措的罗,诬其为抢班夺权的“军队中的赫鲁晓夫”,是毛利用军内将帅矛盾联手林周叶的重大政治战役。整罗,也是对周的警示。罗案曾是中共建政史的最大谜案之一,亦被当作林彪与毛交易陷害忠良的罪证。邱会作吴法宪李作鹏回忆录的问世与相关档案资料的公开,罗案的庐山面目显露真容。朱德对罗案将导致“党内不平安”的感叹一语成真。罗案后,林叶杨取代贺罗,叶是罗案的关键参与者与受益者。杨亦举足轻重,为军中翘楚。罗案则是文革内乱大动荡的真正开端。

文化大革命沉思之十八

另一条战线是文。通过意识形态控制社会是毛时代的重要特征。毛深知意识形态的政治功能及影响力。造舆论是夺权的先声。毛发动党内清洗与政治运动的惯例,是首先占据意识形态的制高点。名不正言不顺。65年初毛秘授江青先通过华东局后找上海市委谋划的姚文元评新编历史剧《海瑞罢官》的大批判文章,刊于65年11月《文汇报》,几乎与罗案同时,被官方和学界认为是毛发动文革的信号。这篇文章批判的重点是明代清官海瑞的“退田”,影射六十年代初的分田单干。毛讲《海瑞罢官》的要害是罢官,是右倾翻案风的产物,影射庐山会议罢了为民请命的彭德怀的官。“替今日的海瑞招魂”。彭即当代海瑞。几乎同时,彭被毛劝说离京到西南任职。尽管作为文革信号的姚文在当时只有极少数极少数人知其政治含义,邓小平依旧找吴晗打牌,周恩来将姚文转载于《人民日报》第五版的学术栏,试图将其向学术论争方向引导。被毛誉为“红秀才”评海文的另一个重要信号,是一直在幕后的毛夫人江青的政治亮相。“露峥嵘”。但历史将昭示,缓解大饥荒的经济政策对患有意识形态僵化症与妄想症的毛而言,是新一轮政治整肃的突破口。其罪名是“修正主义”。

文化大革命沉思之十九

历史与文艺,是毛式阶级斗争意识形态的两大重心。从四十年代延安文艺座谈会上的毛讲话到66年初江青的部队文艺座谈会纪要,其主旨都是文艺为政治服务,为权力需要服务。江青的这个纪要,把文艺政治化到“尖锐阶级斗争”的程度,以文艺问题为政治问题,锋芒直指陆周的中宣部文化部,开辟了攻击刘邓陆的文化舆论战线,是中共建政以后批《武训传》、批胡风、批胡适、批俞平伯、批丁冯的继续,其否定文革前十七年的文艺创作,否定中国、欧洲与俄罗斯的古典作品,否定苏联的经典作品如肖洛霍夫《静静的顿河》,否定三十年代的国防文学,达到“我花开來百花杀”的地步,堪称全盘推倒所谓“封资修”即人类艺术成果的文艺虚无主义的典范。其中提及接受斯大林的所谓教训竟然是斯大林无批判地继承了俄罗斯与欧洲的经典著作。纪要经毛多次修改并以“林彪同志委托”向全军全党以中共中央名义正式批发。毛邀请林彪这个“尊神”为其夫人助威。江青从此以创造京剧革命的“文艺旗手”的身份称霸文坛,闯进政坛,呼风唤雨,并以文艺文化为利器向彭真限制文革的《二月提纲》开刀,文革夫妻店敲响了毀灭文化自我膨胀的震天锣鼓。

文化大革命沉思之二十

林、周是毛发动文革稳定军政的柱石,没有林、周的支持,文革难以发动,发动了也难以控制。林、周在文革前期对毛的辅助是不可缺少的政治支持,故其对文革的灾难亦有难以推卸的责任。也是林、周,后来却成了文革的制约因素。69年九大以后的毛林分歧以林71年9月13日出逃苏蒙实践了高岗、彭德怀里通苏共的罪名,震骇中外。林案的扑朔迷离演绎为当世的拍案惊奇。毛主持的对林的揭露批判令国人大吃一惊,原来这位最亲密的战友接班人私下对毛腹诽最多最尖刻,“妄议”毛的个人品质与政治诡计,不是愚忠,而是利忠,利用之利也。“主先臣后”、“主倡臣和”……林以宫廷政治的诈术对毛。作为林政变纲领印发全党的五七一工程纪要的批林文件竟是一篇石破天惊鞭辟入里的讨毛檄文,道出了毛式整人政治的真相,直指毛为秦始皇,毛时代为秦皇时代……毛苦心虚构的文革理论顿时破灭为举国的笑柄,所谓反修防修的伟大革命,所谓文革理想的五七指示,不过是烟幕。在人们的心目中沦为宫廷的权力角逐。最最革命的话语后面是“封建复辟”。无论张春桥辈如何妙笔生花,罕有人信以为真了。而周,以其老成稳重鹤立为众望所归的人民领袖,与二次出山的邓共同为结束文革进行了思想与组织准备。

文化大革命沉思之二十一

文革纲领一一五一六通知后两天,518林彪的“政变”讲话讲透了毛的心事,是这个通知的注释。从64年底到66年初,毛在党内高层和与外宾谈话中讲了一年多“修正主义”、“造反”、“反革命复辟与政变”的危言,毛断言“修正主义”是“国内外资产阶级反共反革命反人民的思潮在我们党内的反映”。甚至鼓励地方学蔡谔造反。林的讲话,是对毛的响应与呼应,是政治警告(“在他身后,如果有谁做赫鲁晓夫那样的秘密报告,一定是野心家,一定是大坏蛋,全党共诛之,全国共诛之”),亦是政治动员(最大的问题,是防止反革命政变,防止颠覆)。作为军人政治家,林在文革初的讲话较直白地说明了毛的真实想法。如传世的名言“政权就是镇压之权”。林的权力学忠实地折射了毛的权力观。这是研究文革时值得特別关注的。周也讲了反革命政变问题。与此同时,为应对毛因一线中央控制而忧虑首都已非安全之所,防范“修正主义”占领北京,周恩來受毛委托秘密组建并始终控制首都工作组,叶为组长,杨成武谢富治为副组长,其主要成员来自总参作战部,调兵布将,改组扩大北京卫戍区,增加到四师一团,调动70师、189师进驻南苑长辛店清河地区,全面接管北京的安全保卫,直接对毛负责,其所发文件均属绝密级,以让65年3月离京南去的毛放心回京。首都工作组为毛发动文革时期的一着重棋。

文化大革命反思之二十二

66年6月到8月,毛决定公开播放北京大学聂元梓等批判北大党委与北京市委大学部的一张大字报并亲笔复信清华附中的红卫兵,这是文革的动员令,召唤出“造反有理”的大规模红卫兵运动。因势利导,毛在天安门城楼八次接见1000余万红卫兵及宋彬彬为毛戴上红卫兵袖章,将造反之火引向刘邓一线及各级当权派。因停课与免费交通,红五类为主体的红卫兵运动以大串联的方式迅猛席卷全国。从幼儿园开始就接受革命暴力、领袖神话与阶级斗争价值观的大中学生狂热地卷进毛为总司令的造反运动,文革初期的打、砸、抢、烧、斗、抓、关、杀、抄家、掘墓及无所不在的语言暴力,多为青春燥动的红卫兵所为,充分显现了暴力仇恨教育下泯灭人性的少年人的残忍性和蒙昧性。这是长期运动施政的后果,是中国历史上极其恥辱的一页。北京高校率先造反并在反工作组压迫中受毛支持而崛起的五大领袖(聂元梓蒯大富韩爱晶王大宾谭厚兰),独领风骚名噪一时,为文革势力所利用而深深卷入了高层的政治内讧并于九大以后陆续作为政治牺牲品身陷漫长的牢管之灾。长期受歧视的社会弱势群体地富反坏右受到所谓革命群众的集体迫害和无妄之灾。其子女亦因血统论而饱受凌辱。北京大兴惨案与湖南道县惨案只是两个文革初期的典型案例。这是十年文革中最受屈辱最悲惨的社群。

文化大革命沉思二十三

文革之初的工作组与反工作组之争反映了毛刘不同的文革观。刘以为毛发动的文革是新一轮反右运动,故其主持的中央以传统的派工作组方法处理首都学校日益失控的造反活动,计划打出三、四十万个右派分子。因为响应毛“四大”(大鸣大放大字报大辩论)号召起来造反的攻击对象往往是各单位的党政领导,从而造成难以避免的乱象。如北京大学的乱批乱斗。工作组理所当然把这些造反分子当做新右派来清查处理。王光美顾问的清华大学工作组对蒯大富就是这样的立场。文革打开了当时社会冲突与积怨的潘多拉之盒,各地的造反派以毛的文革思想与516通知为指南表达各自的不满与利益诉求,与地方党政领导冲突不断,后者对前者的压制亦沿用了一贯的反右模式。而毛的文革目的是全盘改组甚至清洗从刘邓中央一线到地方的党政军当权派,树立自己的绝对权威,因为毛视刘邓为异己的、失控的、变修的党政官僚集团的代表,是革命对象,毛要通过自下而上的群众运动重新造党造军造政府,使之完全成为自己意志的随心所欲的工具。林彪讲文革是罢官运动,组织问题是政权问题。“对主席的指示要坚决执行,理解的要执行,不理解的也要执行”。陶铸讲,“不是毛主席的党我们就打倒”。这是文革的实质。通过文革纲领的516通知时,刘是会议主持人,讲:“开政治局扩大会议叫大家讨论,提了意见不改,连几个字都不改,这不是独断专行吗?”。这就是毛的乾纲独断。

文化大革命沉思之二十四

红卫兵(捍卫毛泽东思想的红色卫兵)运动的“大闹天宫”达到了甚至超出了毛的“天下大乱”的预期,66年12月26日,毛与江青、陈伯达、张春桥、王力、关锋、戚本禹、姚文元在中南海过七十三岁生日并为他的心腹干将祝酒:祝全国全面的阶级斗争。67年1月上海由安亭事件引发的夺权风暴使这一年成为文革最动荡而血腥“怀疑一切,全面内战”的岁月。王洪文呼啸而出。夺权按照毛的意图和布署在全国范围内展开,文革从学生为主体的红卫兵阶段进入工农兵为主体的造反派阶段,激进的造反势力与当时党政军权力当局相关的相对保守的势力都在毛泽东的旗帜下卷进充斥暴力的派性之争,中央文革则为激进造反者的主导者与坚强后盾。中央乃至地方的党政机关多在造反群众的冲击下陷入瘫痪。而夺权背后的派性斗争激化了旧制度社会各阶层的矛盾尤其是官民矛盾,也恶化了各类历史的与现实的及民族的人间嫌怨,以革命的名义发生的人性灾难遍及神洲大地。野蛮的丛林法则支配了仇恨的政治世界。泛政治化的意识形态堂皇论争较量后面掩饰了权欲的狡诈与贪婪。文革中的两面人格是毛时代独特的人性变态。1966年下半年以北京为中心的打砸抢抄抓、67年下半年以武汉为代表的全国血腥武斗与68年下半年开始的清查是文革中三个恐怖时期。而率先造反的北京各路领袖,则在中央文革的授意下把矛头指向毛反复抨击的“睡在身边的赫鲁晓夫”刘少奇,组织了声势浩大的包围中南海的“揪刘火线”。

文化大革命沉思之二十五

刘少奇从被审查直到惨死开封的结局,说明毛的阶级斗争政治发展到极致,即使是党内最高层,也难幸免,人人胆颤心惊,朝不保夕,党内斗争如此残酷、如此冷血、如此不可理喻,世所罕见。中南海外,揪刘火线的喇叭震天轰响,中南海内,在毛女儿组织的批斗会上,刘与全家受尽羞辱,死前含愤抗议以至拒绝医治,血管无下针处,发长数尺,仍被令其生命治疗延续到听读“叛徒内奸工贼”并永远开除出党的八届十二中全会决定。人世之辱,莫此为甚。难以测知刘在临终之际如何感叹人生如何追思往事,延安时期就辅佐毛打天下,为毛护法,为毛造神,竭智尽忠,呕心沥血,一旦分歧,黄泉相见,党治人治之噬人自噬,为二十世纪中国的最大悲剧。这个悲剧说明中共政治制度化的严重缺陷。其一,党内缺乏有效监督最高领袖的体制机制,其二,党内缺乏文明理性处理高层政治分歧的体制机制。因此,党极易变成领袖的工具而难以自行纠错。组织的神圣化与领袖的神化是毛时代的两个政治陷阱,多少罪恶,多少人伦灾变,假组织、领袖与革命的名义发生。毛刘的政治悲剧值得永远回味。

文化大革命沉思之二十六

文革中最动荡的一幕戏是67年的夺印。夺权,谁來夺权,导致从中央到地方党政当权集团与夺权造反势力的对立,利害不同的造反群众亦分化为因阶级斗争的政治理念而誓不两立的两派或多派。夺权时期发生了对各级党政干部的游街戴高帽喷气式关押围殴等批斗场景,也有地方当权者动员工农围攻造反学生……其混乱是必然的,因为谁是造反派,谁是保守派,谁是毛派,谁是反毛派,谁是文革派,谁是反文革派,谁是革命派,谁是反动派,谁是左派,谁是右派,并无明确的标准与裁判的规则。他们信奉的都是黑白分明你死我活的阶级革命价值观。故其政治争斗亦无章可循,更无妥协之伦理。派性斗争撕裂社会,其影响不止于文革,为文革的恶果之一。全国的情况千差万别,但也可发现某种共同性。如地方党政权力与地方军区往往有密切的关系,与野战部队则较有距离。如保定武斗的军方背景。对地方党政的造反冲击也难免波及地方军区甚至冲击军事机关,后者在局部地区则用军事手段压制造反派,如青海赵永夫事件和成都军区的“二月镇反”。而武汉的七二O事件,则把这种大民主的群众对立推向白热化,惊动中枢,震憾全国,演变为文革群众性动乱由盛至衰的转折点。

文化大革命反思之二十七

67年2月反击所谓二月逆流后,江青的文革小组取代了周的碰头会,毛的“天下大乱”与夺权政策引起全国范围内尤其各大省会城市的愈演愈烈的派别武斗。其中武汉事件尤为突出。7月,毛亲自坐镇武汉,处理武汉的派別冲突,试图树立一个典型。几乎同时,武汉发生了造反派的大游行与保守派百万雄狮对游行的冲击,死伤百人。毛决定把武汉军区与省军区独立师支持并参与的百万雄狮定为保守组织,对立派别三钢三新为革命造反派,以后者为中心实现大联合,并要求陈再道领导的武汉军区释放被关押的造反派领袖。消息传出,群情激愤。周恩来对陈讲武汉军区犯支左方向错误,遭陈顶撞。周走后,大量军人(8201独立师、8199部队及军校)卷入的百万雄狮持冲锋枪长矛大刀冲进东湖宾馆中央代表团驻地,误殴陈再道,拳打脚踢后绑走了中央文革代表王力,游斗十余小时,骂退谢富治(“谢富治是个大坏蛋,抓住他,揍死他”),困毛于东湖客舍。牛怀龙蔡炳臣坐视不问。百万雄狮近百万人连日荷枪实弹浩浩荡荡环武汉三镇武装大游行,其中百余辆军车,车头架着轻重机枪,高喊“打倒谢富治,绞死王力,枪毙余立金”“揪出中央文革中一小撮坏蛋”“要陈再道,不要谢富治”“揪出谢富治的黑后台周恩来”“质问陈伯达”的口号,亦有质问毛的言论,向中央施压,挟制中央改变对武汉派别性质的认定与处理方针。其标语有“毛主席受了蒙蔽”。武汉全城如节日狂宴,呼声震天。毛下令找回王力,警车出动482辆,消防警报响彻武汉上空。是夜,武汉全城回响着“百万雄狮过大江,牛鬼蛇神一扫光”的吼叫。

文化大革命沉思之二十八

武汉事件震惊了北京。江青惊慌失措,以为陈再道“兵变”,劫持了毛。林、周商议后,林亲笔致信毛要毛转移,着手相应的军事布署,周赴武汉劝毛离开。这是中共建政以后毛头一次被迫离开一个城市,避往上海。七二O事件后,毛判断百分之七十五以上的军队首脑都是支持党政右派的,他以毛润之的署名私自致信江青,提出武装左派,实行群众专政,支持揪“军内一小撮”。这是江青号召“文攻武卫”的依据。林彪要批判“带枪的刘邓路线”。文革从造反有理、打倒一切进入全面内战的时期。各地爆发的大规模武斗与死伤事件多发生在这个时期,发枪与抢枪,甚至劫抢援越军用物资,接管监狱,阻断铁路,炸桥,抢劫银行、仓库、商场,局面开始失控。毛感叹文化大革命变成武化大革命。这是文革最动荡最血腥的阶段。毛面临前所未有的困局,被迫对造反夺权降溫,强调自上而下三结合,以军队为主,老干部与革命群众代表都是结合对象。依靠林彪对动荡地区实行全面的军管。派军宣队工宣队接管学校。认为攻周的首都五一六红卫兵团为“反动组织”,甚至要批评极左派思想。所以,七二O事件是文革群众性动乱从盛转衰的转折点,在短期的疯狂过后,毛从鼓动群众造反到强调革命大联合,最激进的造反派开始走向衰亡。8月26日毛下令逮捕文革要员王关戚,不久前王力曾是武汉事件的英雄,从武汉回北京受到林彪、江青安排的百万军民凯旋式欢迎。谁能导演这样的人间戏剧?

文化大革命沉思之二十九

武汉事件是文革政治史富有启发意义的典章,其对文革的进程影响甚巨。文革对毛,也是“摸着石头过河”。它释放了文革前被压抑的各种力量、各种利害、各种矛盾,各种冲突,其暴力强度匪夷所思,称之内战并不夸张。两派对立势同水火,生死相拼,是一次人为权死的总爆发。毛深夜二时转移到王家墩机场,黯然飞沪后,怒称东湖是贼窝,七二O是反革命兵谏。毛是深知事件之性质与严重性的。将影响到南京军区、福州军区,不仅是武汉的问题,是全国的问题。周讲是家丑,“百万雄狮是对着中央来的……建国以来从未发生这种情况”。林彪将七二O事件定为反革命暴乱。困兽犹斗,有武汉军区与地方独立师深度介入的百万雄狮为其政治命运挺而走险,清君测要挟中央,几危元首,确是惊心动魄的政治辣剧。武汉人的火炉脾性充沛展现。各种势力各类人物之表演淋漓尽致,活龙活现,笔墨难述。据邱会作回忆,事传北京,江青向叶群哭诉“反革命分子已经快冲到主席住处,高喊’抓住那个胖子!打死那个胖子’!他们喊的那个胖子就是主席”,要求林叶亲去武汉护驾。周率中央警卫团人员赴汉,王家墩机场被占,其专机只好改降山坡机场,周化装后急奔东湖救驾,帅府千金有挥泪别红颜之传闻,王力评论8201部队的特别呼吁:“这是反革命宣言书。这回独立师可真是独立了,向毛主席独立,向解放军独立”,陈再道、钟汉华事后检查对毛的安全不闻不问,“以蒋介石的态度对待主席”……毛对于自己释放出来的革命魔鬼,已近失控了。

文化大革命沉思之三十

武汉事件三十余年后,烟消雾散,已过不惑之年的当年敌对派別的代表人物曾经聚首江城,杯酒交错,相逢一笑泯恩仇,往事历历堪回首,其话题离不开激情燃烧的七二O事件,百万雄狮的当事者坦承:项庄舞剑、意在毛公。可见证毛、林、周、江对武汉严重局势的估计是准确的,军队的分裂与地方的独立,是严重的危机。以毛的绝对权威,摆不平武汉一个群众组织的抗命,差点演变成军队的火并。当权的地方党政军集团仍有左右局势的实力且并不甘愿俯首被黑,更不甘愿任由昔日臣民的摆布。据我观察,被斗被关被审查的老干部心服口服者少之又少。七二O事件后,据统计被打伤打残打死人数多达十八万四千人。毛在武装左派重组军队的激进举措之同时,亦保留了几分清醒的头脑,如保护陈再道钟汉华,争取大多数,很快停止“军内一小撮”口号的使用,令张春桥从大别山请回许世友,在火烧英国代办处的外交事件后,毛听从周的建议,果断逮捕文革激进派王关戚,为文革狂热适度降溫,在全国范围内停止大串联,制止武斗,复课,派工宣队军宣队接管武斗的高校,为造反派开办学习班,并亲自召集京城五大造反领袖训话,演出了喜怒交加的惨淡的闭幕场景。

文化大革命沉思之三十

武汉事件三十余年后,烟消雾散,已过不惑之年的当年敌对派別的代表人物曾经聚首江城,杯酒交错,相逢一笑泯恩仇,往事历历堪回首,其话题离不开激情燃烧的七二O事件,百万雄狮的当事者坦承:项庄舞剑、意在毛公。可见证毛、林、周、江对武汉严重局势的估计是准确的,军队的分裂与地方的独立,是严重的危机。以毛的绝对权威,摆不平武汉一个群众组织的抗命,差点演变成军队的火并。当权的地方党政军集团仍有左右局势的实力且并不甘愿俯首被黑,更不甘愿任由昔日臣民的摆布。据我观察,被斗被关被审查的老干部心服口服者少之又少。七二O事件后,据统计被打伤打残打死人数多达十八万四千人。毛在武装左派重组军队的激进举措之同时,亦保留了几分清醒的头脑,如保护陈再道钟汉华,争取大多数,很快停止”军内一小撮”口号的使用,令张春桥从大别山请回许世友,在火烧英国代办处的外交事件后,毛听从周的建议,果断逮捕文革激进派王关戚,为文革狂热适度降溫,在全国范围内停止大串联,制止武斗,复课,派工宣队军宣队接管武斗的高校,为造反派开办学习班,并亲自召集京城五大造反领袖训话,演出了喜怒交加的惨淡的闭幕场景。

文化大革命沉思三十一

学生停课闹反的疯野岁月最多两年,到67年的夺权风暴中程度不同卷入武斗的混战,已非运动的主流。到68年上半年,从中央到地方的成批当权者或管制或关牢或下放,在党内诸敌扫荡之后,毛着手恢复秩序,6月向各大军区省军区派驻了中央支左部队,平息武斗,督促大联合。毛对造反学生开始厌倦了,亲派中央警卫团官兵与工人进驻清华,为蒯大富武斗所阻,死五人,伤731人。7月28日,毛在林周江康陈谢黄陪同下召见北京五大造反领袖聂韩蒯王谭,进行严厉的训话,自称”黑手”。毛怒斥造反学生武斗不得人心,警告说:”现在是轮到小将犯错误的时侯了”。并厉声宣布:”谁如果还继续违犯,打解放军、破坏交通、杀人、放火,就是犯罪。如果有少数人不听劝阻,坚持不改,就是土匪,就是国民党,就要包围起来,还继续顽抗,就要实行歼灭。”。毛的训话杀机毕露,意味着毛要收回造反的猴毛了,学生退场,军人上场,军政时代开始,文革秩序,以军管启幕。毛在对姚文元文的批语中称:凡是知识分子成堆的地方,不论是学校,还是別的单位,都应有工人、解放军开进去,打破知识分子独霸的一统天下。毛强调,大批判和清理阶级队伍,为整党创造了最好的条件。所谓整党,就是建立文革秩序。

文化大革命沉思之三十二

从68年5月开始的清理阶级队伍,是转嫁文革危机以恢复秩序的传统作法。以文革时期的政治思想与政治思维,就是沒有中央文革的干预,各派政治力量也是难以实现权力分享的所谓革命大联合的。造反派显然不具备罗伯特议事规则的文明素质。阶级斗争意识与暴力革命传统只会使各路造反派更加敌视更加对抗。和平对话妥協让步服从规则是与毛式革命格格不入的。派性,是文革政治的必然。所谓大民主,是毛利用群众整肃政敌的政治手段。毛式运动的后期,总要秋后算帐,总会伴随一个恐怖的肃反阶段。因此,清队是革命转向造反指挥系统与造反派内部的标志,打击对象是所谓死不改悔的走资派与所谓未改造好的地富反坏右分子。虽然有政治表现论,但翻阅毛林周江康等在文革时期的讲话,追查出身并以出身为犯罪犯错根源之论调比比皆是,这是文革中特有的两面现象,而清理阶级队伍,就是从党政军首脑机关及造反队伍中清出不听话不顺从的异己分子,出身、家庭与历史”有问题”的人,首当其冲。利用清队挟嫌报复者,亦不在少数,是文革中的反右运动。其间发生的五一六冤案,受屈者多为有异议的造反派,牵及百万之众,后果惨重,遗患无穷,是文革中非常阴暗的一页。

文化大革命沉思之三十三

毛文革前曾对刘说:”你有什么了不起,我动一个小指头就可以把你打倒!”这个小指头却是十年清算。文革大致有三个阶段,造反有理、全面内战的66-68,这三年是社会大动荡时期。69-71年为第二阶段,是军管与军政时期。72-76年是衰亡的最后阶段。从66年8月《炮打司令部》的大字报到68年10月八届二中全会决定以”叛徒”、”内奸”、”工贼”的罪名将刘少奇永远开除出党,毛以亿万人卷入大动乱的巨大代价完成了对刘少奇的彻底清算,达到了文革的预期目标。《炮打司令部》以蒯大富提供的材料指控刘邓围剿造反派,”联系到1962的右倾和1964年形左实右”,可窥察毛刘分歧的历史轨迹,62年为关键。67年《红旗》5期刊发的经毛审核的戚本禹的批刘长文《爱国主义还是卖国主义?一一评反动影片<清宫秘史>》,向刘少奇提出了八个为什么,其中重大政治指控是刘在抗战后提出”和平民主新阶段”、建政后坚持新民主主义反对过急过快搞工商改造与合作化、56年主张阶级斗争熄灭论、三年大饥荒时期推行”三自一包”、”三和一少”的内外调整政策……戚的指控从另一个革命大批判的视角反射了从45年到66年毛刘的一些重大分歧,终于爆发于64年的社教运动,65年毛开始设局铲除刘少奇。戚文是文革中官方首次指名道姓系统批判刘少奇的文章。刘阅后极为愤怒,致信毛为自己申辩,后又写了对”八大罪状”的答辩,均被置之不理。

文化大革命沉思之三十四

刘案株连其妻王光美。文革中株连极其广泛,专案组不计其数,外调内查,冤及亿人。刘案专案人员前后近40万。王与江,是文革前与文革中领袖夫人介入政治的范例。王因桃园经验名扬天下,又与清华结下不解之缘。67年4月,清华大学组织了三十万人的批王大会,其间《三审王光美》流传甚广,传达的信息亦很丰富。关于《清宫秘史》,王答刘未说是爱国主义,关于天津讲话,王答刘是毛派去纠偏的,当时讲剥削有利生产是需要的,关于战后和平民主,王答非一人责任,刘勇于担责,关于后十条,王答刘修改的,精神是好的,关于蒯大富,王答刘未说未定蒯是反革命,关于桃园经验,王答成绩多缺点少,关于红色资本家,王答非刘讲,谁说的保密,关于戚文,王答刘不承认自己是反革命……今天重观《三审王光美》,感觉王这位曾是辅仁大学留美的博士侯选人在群众围攻的压力下据实申述,实为难能可贵,有大家闺秀之风范。70年6月,刘王专案组定王为美国特务,江青要毛判其死刑,毛批”保留活证据”……文革十年,王囹圄十年。出狱后白发苍苍,未闻王对文革有多少深刻反思,是为憾事。毛倒刘念了两个魔咒,一个是赫鲁晓夫,一个是资本主义复辟,前者刘沾点边,后者与刘无缘,但刘的天津讲话有卓见。另外,毛的魔咒是有效的,迄今党内无人敢做毛的”秘密报告”。

文化大革命沉思之三十五

值得一提的是,与清队同时,67年下半年全国各地还涌出了所谓二月逆流以來又一次非议中央文革的”右倾翻案风”,似是文革中第一次右倾翻案风,如,江西多城市公开号召为刘邓陶翻案,国防科委的”多中心论”,上海有群众组织为陈丕显曹荻秋”鸣冤叫屈”,天津为陈里宁周杨翻案,内蒙为乌兰夫翻案,河南安阳高悬刘少奇像,南京为谭震林翻案,清华有人支持蒋南翔刘冰,外交部保护陈毅的大字报,北京有学生为二月逆流翻案,与之相反,上海炮打”大叛徒”张春桥声势浩大,北京等多地炮打谢富治,四川群众打倒中央文革支持的刘结挺张西挺……江青断言”目前右倾翻案是主要危险”。共产党员张志新,文革中挺身而出质疑毛江,批评林彪的顶峰论,为刘声辩,与抨击出身论主张人人身份平等反对等级歧视社会的思想先驱一一中学生遇罗克,为不朽的双杰。杨余傅事件后,北京造反派追究陈叶聂,叶住地受围困……68年3月,黄永胜任军委办事组组长,林受命稳定京都,军管四方,从上到下大多数革命委员会,实为军管会,主要领导均为上面指派,原有的夺权设想全面失败,造反派未实现打江山坐江山的梦想,军队干部主宰乾坤,军队干部90%以上参加过支左军管。全国山河一片红,毛虽志得意满又心事重重,民国折腾成军国,举国疮痍,九大不能再拖了。

文化大革命沉思之三十六

从56年中共八大到69年中共九大,十三年间未开过一次党代表大会,是中共历史上极不正常的政治状态。因为毛对八大中央有疏离乃至不滿。八大甫过,毛即对八大政治报告关于中国社会基本矛盾的判断表示异议,文革中则谣传刘背着毛起草并匆匆忙忙通过政治报告。文革之初,王光美面对造反派对八大政治报告的质疑,曾说,主席没看过?不过文件出来很久了,毛主席、党中央未表态。57年反右以后,毛以阶级斗争的主要矛盾论取代了八大的生产力论,58年向自然开战的高指标大跃进与共产主义实验的公共食堂导致四年大饥荒,闯下秦皇以来未有的巨祸。从59年庐山会议到62年七千人大会,党内外议论纷纷,怨声载道,毛隐忍退守。此时按例召开党代表大会,显然对毛不利。62年以后几年,为经济调整与经济恢复时期,刘主持的中央一线殚精竭虑于经济建设与科学发展,毛却日益焦虑大权旁落与赫氏的死后鞭尸以及接班人问题,故从社教迂回攻击中央一线,以反修防修为名发动文革,其中亦有利用群众反官僚特权腐化的因素,引起天下大乱,党政组织瘫痪,夺权与反夺权,全面内战,难以收场,68年借重林彪军管后,局面才趋于稳定,毛要通过全会与大会把文革合法化,同时确立新的领导层。

文化大革命沉思之三十七

68年10月召开了九大的准备会八届十二中全会,这个全会出席的委员不足半数,会前康生密信江青,八届中委候补中委有严重历史问题的(叛徒特务里通外国)占总数71%,毛讲八大刘少奇招降纳叛。故,全会只好增补中委,凑足半数。周讲话强调了两部分出席者,一是中央文革碰头会成员陈康江张姚,一是军委办事组黄吴叶李邱刘贤权,全会有两大主题,一是批判对一月夺权冲击老干部不满的元勋重臣,包括聂荣臻、叶剑英、陈毅、徐向前、贺龙、李先念。毛开幕讲话指全会应肯定文革的必要性。这是毛最关心的。周恩来讲,陈毅大骂红卫兵,说”我的检查是逼出来的”。叶剑英未制止其女儿冲击军科院,在67年1月座谈会上拍桌子拍断了骨头,讨论八条时反中央文革,自称”今天是舌战群儒”,李先念立即起哄,”不愧为元帅叶参座”。聂讲抓高干子弟是”不教而诛”。赵永夫打死三百多人,叶发电祝贺。把造反派当敌人。徐向前对在三座门静座几昼夜的学生评论说:”冻死了活该,多冻死几个”。聂荣臻搞”多中心论”,把国防科委搞成独立王国。陈云的女儿陈伟立徐向前的女儿徐鲁滨直接攻击毛与林……他们保护的是刘邓司令部。在分组会上,朱德被黄永胜指控”有野心”、”想当领袖”,康生批二月逆流是反毛,为王明翻案,否定延安整风,谢富治称:”朱德同志从到井冈山第一天起就反毛主席”……这些批判的目的,是排除异见,舆论一律。林彪总结说:二月逆流是十一中会以后一次最严重的反党事件,”文化革命成绩最大最大最大,损失最小最小最小”,树立毛的权威。另一目的,是为九届一中全会不选或少选这些开国元勋进政治局制造舆论。

文化大革命沉思之三十八

八届十二中全会的另一个主题也是最重要的议题,是审查通过中央专案审查小组的《关于叛徒、内奸、工贼刘少奇罪行的审查报告》,决定将刘少奇”永远开除出党,撤销其党内外一切职务”。刘案原由周恩来负责,因拖延不决而毛授命江青负责,江以逼供信的伪证编制三本刘少奇被捕叛变的”罪证材料”,报送中央。具体负责专案的谢富治说:”大叛徒刘少奇一案,主要工作都是江青亲自抓的。今后一切重要情况的报告和请示都要直接先报告江青同志”。周在审议中小心翼翼,与江、康多次争论,在毛的高压下,同意了江青的定案,表示”向你学习”,并以专案组长的身份在全会上作了审查报告。耐心寻味的是,林在报告上批了”向出色地指导专案工作并取得巨大成绩的江青同志致敬”。表决时,全会只有一个陈少敏未举手。文革后,胡耀邦高度评价陈少敏的气节,在当时政治气氛下,确属不易。69年10月,刘被押送开封,11月12日,死于囚禁中。因刘案受株连冤案共22053件。毛从62年开始的清算”赫鲁晓夫式野心家阴谋家”的政治工程至此大功告成。文革中真正陷人于死无葬身之地的,就是所谓历史问题。刘案只是其中一个最典型的案例。还有一个细节值得一提,也对中国政治进程将产生重大影响,全会闭幕的时候,毛建议保留邓小平党籍。区別刘邓。毛发动文革时曾讲邓是刘司令部里摇鹅毛羽扇的。

文化大革命沉思之三十九

九大之前,改朝换代接近完成,混乱局面仍待控制。毛从策略上为文革降溫,强调注意政策,注意调查研究,团结多数,少关不杀,”只要不是杀人、放火、放毒,几个反动标语算什么?教授、讲师不像军队,他们是手无寸铁”。走资派不都是坏人,”我对二月逆流的人不一定恨得起来”,子女可教,以缓和党内外紧张气氛。另一方面,如火如荼的清队在各单位制造阶级斗争与冤假错案,审查全部干部,清华1228人被立案审查,北大抓了九百人。而两校是毛亲自派人(迟群谢静宜)抓的典型。据统计,全国清队期间近20%的干部受到立案审查。革命大批判以批所谓黑六论改造思想,洗脑,其中”人性论”和”唯生产力论”为批判重点,姚文元在给毛的报告中,指苏联修正主义是建立在人道主义和人性之上的,经济上则批判刘少奇的利润挂帅、工分挂帅、计件工资、物质刺激、专家治厂等活跃经济的具体政策。与此同时,大批干部知识分子下放五七干校,大批学生上山下乡,喧嚣的城市空荡起来……69年3月,突然发生中苏珍宝岛战役,中苏关系处在战争状态,几乎引致核战争,以达到转移矛盾、消除派性与国内团结的政治目标……九大筹备期间,为自上而下指派代表,《红旗》刊文批判迷信选举,系出自毛的指示,批判迷信选举的形式主义。外松内紧,九大的全部筹备工作是由中央文革碰头会组织召集的。

文化大革命沉思之四十

69年4月九大在神秘的气氛中开幕。九大的主要任务仍是以党代表大会的形式充分肯定文化大革命。毛在九大期间召集人的一次讲话说:为什么来一次触及上层建筑的文化大革命,”从中央一直搞到工厂、机关、学校,过去这些不都在我们手里,大都在国民党手里,都在资产阶级知识分子手里,而且他们还有后台。”夺权,全面夺权,这就是文革的本意,文革的真实目的。为加强文革的正当性,九大政治报告概述了毛无产阶级专政下继续革命的理论,即马克思主义发展的第三个里程碑。其核心理念是63年归纳的”以阶级斗争为纲”。这个理论主要由张春桥根据政治需要编撰的。张因此被毛重用,作为接班人加以培养。九大主席台阵线分明,有如红白脸古装戏,毛左边有陈伯达、康生、江青、张春桥、姚文元、谢富治、黄永胜、吴法宪、叶群、汪东兴、温玉成,右边是周恩来、董必武、刘伯承、朱德、陈云、李富春、陈毅、李先念、徐向前、聂荣臻、叶剑英。毛在九大筹备期间讲,陈毅代表左中右的右派参加大会。九大对毛营造的个人崇拜达到中共有史以来的顶峰。伴随毛出现的狂热掌声与口号响彻会议始终。这是一次封毛为神的代表大会。与发展生产力为主要任务并反对个人崇拜强调中共集体领导的八大形成了鲜明的对照。

文化大革命沉思之四十一

林彪在九大修改的党章中确立为毛的接班人。这是文革中的荒诞事件之一。高岗事件之后,林大隐隐于朝窥察毛的心机与政术,逐渐揣摩出一套对付与迎合毛的君臣之道,其要旨是”主席划圈我划圈”。他深谙毛的习性与心理,认为毛”自我崇拜,自我迷信,崇拜自己,功为己,过为人。”林深居简出,性格孤傲,少言寡语,亦少交往,对毛的独断政治不容异见体悟甚深,”谁不说假话,谁就得垮台”,是林的肺腑之言,亦是屈身于毛治的政治铁律。林在文革前曾较消极,奉行不轻易骑上去的审慎之道,毛当面批林想当明世宗,林不得不上位,并于八届十一全会的讲话中流露心情沉重,随时准备交班给更合适的同志。据纪登奎回忆,林在文革中少有表现。他奉行”不负责、不建言、不得罪”的消极方针,突出毛,”言不离主席”,”手不离语录”,把送毛的文件由”请”和”送”改为”呈”,大事不麻烦,小事不干扰,对运动事不关已,避之千里。然而,林担有稳定军队的重任,对军队的冲击不容坐视,且严禁江青的文革小组插手军队事务,曾怒责江青乱军,其部属杨成武亦因过于投靠江青而被罢黜,直至913出走,江青未能染指军权。林主拟《军委八条》,与周共同维持大乱中军队与政府运作的基本格局。武汉事件后三个多月间全国武斗升级,局部失控,林恃毛提出”还我长城”,助毛军管,稳定社会秩序,亦使军方的权力膨胀到高峰。

文化大革命沉思之四十二

早在68年,中央成立的以林为主任的党史編委会拟出的《京西大纲》对林有诸如井冈山会师的突出描述,为毛否定。毛林政治分歧始于九大,当时并不为人所知。林彪事件后,周在十大政治报告有所回顾。毛委托林起草九大政治报告,林属意于陈伯达九大后致力于发展生产力的报告构想,主张从人民、国家的角度讲民富国强,周同意,但为毛否决,张、姚受毛委托起草的继续革命报告,反映了毛巩固文革与发展文革的意图,被陈伯达讥讽为”运动是一切”,陈受到毛的粗暴训斥。林结结巴巴在大会上照本宣科了毛修改的张姚报告,并回绝了张春桥请其在报告上签名。毛张姚与林周陈九大后政治目标的分歧虽然未如毛彭与毛刘公开争论却也是性质严重的……毛在九届一中全会上借苏联”攻击”中共”军事官僚体制”即”军事官僚专政”自嘲,其实隐晦地表达了对全国军管后军人坐大的忧虑。九大选出的中委中军头占多数。毛对所有威胁其权威权力的潜在势力都有本能的警觉与防范。据有关回忆,毛在九大其间曾问林,林后的接班人如何考虑?提到张春桥。对张赏识有加。林沉默以对。林对张不屑一顾,多次评其为无名小卒,小记者,不知其冒自何处。毛林在人事上的龃龉,也为九大之后的政治斗争埋下伏笔。据相关回忆,九大后毛曾专赴苏州看林,谈林后谁接班的安排,又提到张,林仍沉默以对。毛林的蜜月注定比毛刘短促。九大开后,毛快七十七了,时不我待。

文化大革命沉思之四十三

九大以后,轰轰烈烈的群众性造反夺权演变为严酷的清队肃反,群众专政被纳入检举揭发告密的无产阶级专政即由工宣队军宣队主持的专案审查,如毛指示,把无产阶级专政落实到厂矿、机关、学校,落实到基层的每一个单位。七十年代初,中国政治又轮回到东西南北中党领导一切的旧轨,群众运动的恐怖被专案系统的恐怖所取代,这是毛式运动的必然归宿。清队的锋芒指向反革命,与”揪叛徒”狂潮相伴随的是清查莫须有的五一六阴谋集团,实为以严格的阶级路线打击前期运动中群雄蜂起的所谓坏人和异己分子,或所谓追求巴黎公社原则的”人民文革”,制造了大量以言定罪的冤假错案件。这种清查延续到文革结束。70年张志新被判无期徒刑。为落实《公安六条》,死刑判决权下放给省市自治区,遇罗克被北京军管会判处死刑。70年十个月就清出叛徒特务反革命184万余人,逮捕28万4千8百人,造反领袖蒯韩王聂谭等先后被关被审或下放改造,兔死狗烹。68年底开始干部知识分子大规模下放五七干校劳动与初高中学生成批成批上山下乡(兵团、插队、农场),接受贫下中农再教育,亿万家庭天各一方,有如生离死別,高校停办,学制缩短,教育、文化中断,样板戏独响神洲,城市短时为老炮的天空。在从喧闹到一片灰冷的社会中,从演戏到观戏,人们将听到高层深宫中传来的汹涌暗潮。

文化大革命沉思之四十四

七十年代末八十年代初由邓陈主持的平反工程,对于中共建政以来的党内大案,只有两个维持原案不变,即反党的高饶案与反革命的林案。尺度是不再定性为路线斗争。不排除邓陈与高林历史上的私怨公恨,但其如此定案主要是维护毛三七的历史评价,保证党内高层的统一与稳定,如胡乔木所言,中共无列宁,毛集列-斯于一身,为维护中共的统治,必须树立毛的历史地位。高林于是为祭品,与之相关的人员也只有蒙冤受屈,含恨九泉。对于集权的中共,政治需要永远是权势者对待历史的指南。毛生前最苦恼的”秘密报告”终于未现,毛的标准像仍高悬于天安门城楼,毛泽东思想作为集体智慧仍是指导思想。林彪做序的毛语录早废弃了,大海航行靠舵手也不唱了。因为两案不动,国内的所谓研究者在毛林问题上多为君讳,以毛之是非为是非,不足为史,不足为信。而林的幽灵仍在祖国的土地上徘徊,本来神秘莫测的林案因而更加神秘,王年一曾慨叹林案关键性的资料甚缺。林家幸存的公主亦成为谜样人物。心理学的定律是,越被掩饰的事物,越会招引人们更大的好奇心。何况关乎千百万人命运的林案呢?好,闲话少说,试看林案一角。

文化大革命沉思之四十五

文革本来是毛为解决接班人问题而发动的一场内乱。因为从意识形态角度观察,很难说毛刘有实质性分歧,也更难说刘有什么修正主义理论与观念。毛刘的分歧主要是具体政策,侧重于经济、管理政策与方法。对毛的文革,刘讲老革命碰到新问题,不晓得如何办,也是老实话。按常理说,八届十二中全会与九大已解决了接班人问题,并把毛的亲密战友写进了党章,白纸黑字,江青也如愿进了政治局,自命为党内第三号人物,文革也该结束了。难道毛又疑心其亲密战友是伯恩施坦考茨基赫鲁晓夫?君王心事有谁知,董狐直笔难写实。以前,毛需要个人崇拜倒刘。现在,毛开始注意个人崇拜鼓手的幕后动机。吴法宪、邱会作与李作鹏回忆录的问世,披露了文革初期到913事件之间高层分歧与较量的不少鲜为人知内幕,以前先是毛江后是邓陈的两面之词增加了第三种从林彪立场的说法,这对全面地了解文革尤其是了解毛林从合作到决裂的过程有所助益。兼听则明,然而,所有当事人的口述与回忆都有政治、思想与心智的局限性,其中较重要的事实务须反复核实,也要结合特定的历史环境与回忆者的处境遭遇辨別其真伪,否则,又会从一个误区进入另一个误区。如,军委办事组与江青的中央文革,是权力之争,还是事关文革的原则之争?其多大程度上反映了毛林的暗斗?邱的回忆,证明黄、吴、李、邱确曾密议联合反江,如九大选举时投江的反对票,这些毛应该是心知肚明的。另外,近来又有戚本禹的回忆,从江青立场回忆文革及王力反思录,张春桥的家信,都是研究与反思不应忽略的材料。

文化大革命沉思之四十六

九大后毛林矛盾的激化是否源于江青与林彪或军委办事组的冲突?或者因为军委办事组的反江俱乐部?因为汪对毛江关系的误导?或因为陈伯达被江蔑视而靠拢林?林与江是否宗派之争?林是否急于抢班夺权?在我看来,有这些因素,但都不是主要的。九大时的毛,面对两个高峰,一个是个人崇拜的高峰,一个是军头涌动的高峰。而林,是军队的代表,是当时政治气氛中众望所归的副帅接班人,与周默契合作,支持周的工作,稳定政局,总揽军权的军委办事组成员都是其忠诚部属。革命革成了“军政府”。作为一代政治枭雄权术大师的毛,不是为左右颂词迷惑的昏君,并未陶醉于胜利与万岁的欢呼中。他从未相信过任何一个战友,也不信正确路线战无不胜的神话,而是心有不安,心有所虑。对林与林的势力深怀戒心,并不在于林是否忠心,而是有了不忠的能力与实力。削军权,为个人崇拜降温,多设制衡,就是他深思熟虑的几步棋。首先,是对林的试探。毛主持九大开幕式时讲到选举大会主席团主席,说:“我推举林彪同志当主席。”林立即站立大声喊:“伟大领袖毛主席当主席。”毛又说:“林彪同志当主席,我当副主席,好不好?”林急忙摆手说:“不好,不好,毛主席当主席,大家同意请举手”。这戏剧性的一幕有深远的意味,拉开了毛林斗法的序曲。

文化大革命沉思之四十七

林从六十年代开始鼓吹对毛的个人崇拜,有力配合了毛对刘邓一线的攻击。到了文革,林对毛的赞美变本加利,又有了许多创新式的提法与语言,国人印象深刻,而且在捧毛时把其个人的命运牢牢隶属于毛,多次在大会小会上讲没有毛就没有他,如果贺龙朱德当权,他早掉头了……毛降温个人崇拜,矛头直指林式语言,九大前曾多次在文件中删去“天才地、创造性地、全面地”三个副词。九大后不久毛到武昌,要人把其住所梅岭一号的毛语录与画像全部摘除,针对林说毛讲话“一句顶一万句”,毛说:“人的一句话怎么能顶一万句呢?一句就是一句,不能是一万句,不能顶,更不能顶那么多,我的话怎么可能有那么大力量,那不是神了吗?”。毛自知不是神,也不甘于空虚的神位。他不愿被架空,高据云端。他还说:“四个伟大,太讨厌”。6月,毛指令中央发出《关于宣传毛主席形像应注意的几个问题》,规定“不要搞忠字化运动”、“不经中央批准,不能再制作毛主席像章”。70年4月,毛删去了两报一刊社论林捧毛的“毛泽东同志是当代的列宁”等“无用的”、“引起别人反感”的用语。毛还让周把人民大会堂的语录牌全部摘去,并当着林面自嘲,这些王八蛋的东西没有了。7月,围绕八一社论毛“亲自缔造”与林“直接指挥”的陈张之争,毛先淡化而后又对汪讲:缔造者不能指挥,能行吗?毛又在忧虑“大权旁落”了。

文化大革命反思之四十八

毛对林的牵制,最紧要的是权力部署。没有权就没有一切,是毛林共同的信条。对周的笼络,是双方的重心,周之地位的举足轻重,于此突显。乱世求良臣,毛林都明白这个道理。早在67年夏,林就建议周主持中央碰头会,限制江青。周在九大发言则讲了毛林井岗山会师的谀词,后为张秀川主持编写的《党内两条路线斗争史》写成“林副主席和毛主席(在井岗山)胜利会师”。党内元勋,似无一人看重江青。九大后,林指令黄吴李邱配合周的工作,后者曾为造反所苦,如许世友在九大直言,老干部都恨造反派,乐得協助彬彬有理资望高深的周。毛亦知江积怨甚多,九大后取消了文革小组,亲荐李德生为军委办事组成员兼总政治部主任,安排许世友、陈锡联进政治局,保邓党籍,留刘陈徐聂叶为军委副主席,组建了陈毅牵头叶徐聂参加的国际问题研究小组,缓和与老同志的关系,对二月逆流老战友们的恩怨已似昨夜秋风,黄河逝水,强调落实政策,反对扩大化。政治场上无永远之敌,亦无永远之友。“利”与“害”二字而已。

文化大革命沉思之四十九

林对毛是否放权的试探是69年10月根据毛关于国际形势有可能突然恶化和基于对战争形势的估计向军委办事组发出的战备令,调动全军进入战备状态,以应对苏军突然袭击。被时任副总参谋长闫仲川编为“第一个号令”。命令发出后以“电话记录”(急件传阅)报毛。据汪回忆毛收到林件后命烧掉,并亲自点火烧之,为汪所阻。周询问林令事,汪以实告之,周默然并随即转告林。回首历史,温故知新。59年毛彭的公开分歧是大跃进的成败利弊,64年毛刘的公开争论是社教主要矛盾。70年毛林的公开争议则是国家主席的设废。为准备四届人大,毛3月提出修改宪法,不设国家主席。如设,建议林彪做。4月,林建议毛任国家主席,“这样做对党内、党外、国内、国外人民的心理状态适合。否则,不适合人民的心理状态。”林还建议副主席可设可不设可多设可少设,自己不宜任副主席。政治局多数赞成林的建议。毛又予以否决:“我不能再作此事,此议不妥。”国家主席之争,撇开问题本身的是非曲直,以林主张设国家主席就认为是抢班夺权的判断不足为取,林及支持者从未提出过林出任国家主席的主张,只有康生说过毛不做林做的意见,九届二中全会毛林分野,康生以养病为名躺倒不干了。我以为,林设国家主席的建议是对毛的又一次信任试探。另外,林周等谁也猜不透毛想不想做国家主席。万一毛想做呢?毛林分歧的关节点不在于此。

文化大革命沉思之五十

九届二中全会前发生在宪法修改小组的吴张争吵可看作毛林角逐的前哨战。70年8月,张体察圣意,在修宪讨论时建议在国家机构一章中删掉出自林彪的“毛泽东思想是全国一切工作的指导方针”。吴法宪“一触即跳”维护林彪,指控张违背八届十一中全会决议,坚守被张讥为讽刺的林捧毛的三个副词,说“要防止有人利用毛主席的伟大谦虚来贬低毛泽东思想。”林支持吴,并要求陈、黄、李支持吴,查找马恩列天才语录批张。周亦对吴表示支持,即把“以毛泽东思想为指针”写入宪法。文革时期的党代表大会与中央全会比文革前更保密也更神秘,毛江以此为傲,讲坏人被清洗了,无人泄密。而这时代的民众却是政治敏感性最高的,几乎人人是政治动物,因而对神秘的中央政治更为好奇与关心。林案比刘案更诡异,几乎看不到什么思想上的交锋,文字戏法里面刀光剑影,似是夺权与反夺权的宫廷戏,所以难以责怪人们窥视毛林内斗的好奇与关注。官方修史,语焉不详,或张冠李戴,只讲其一,不说其二,造成更大的混乱。还原真相,乃研史首旨。毛林斗法是从清君侧与清相侧开始公开化和激化的。又是一场发生在庐山的恶斗,较之59年为民请命的悲壮的彭“海瑞”,这次更似一场闹剧。

文化大革命沉思之五十一

70年8月在庐山召开的九届二中全会,宣告了毛林四十余年亲密合作的正式终结。与十一前的那次会议一样,开始也有点神仙会的气氛。全会召开前的常委会,五个常委除毛外均赞成设国家主席,实现党的主席兼任国家主席的一元化。林在开幕式上的讲话,坚持宪法中设国家主席的意见,坚持毛任国家主席以确立其伟大领袖、国家元首、最高统帅的地位,以此为“宪法的灵魂”,坚持毛的天才论及毛思想作为全国人民指导思想。林讲到体制功能的一段话较经典:“在我们这个国家,无产阶级专政的国家,共产党当权的国家,最高的一声号令,一股风吹下去,就把整个的事情改变面貌、改变面貌、改变面貌。”那么,林指的什么风呢?据知情人回忆,林的讲话是与毛商量过的,毛讲不要点名。林讲完,掌声雷动,许世友陈锡联跑去与林握手,康生接着讲,他完全赞成林讲话并说:“如果主席不当国家主席,那么请林副主席当国家主席”。这是国家主席讨论中难一可见的荐林为国家主席公开发言。经吴法宪提议,全会收听林讲话录音,分组讨论林讲话。当夜,陈伯达编出恩列毛林论天才的语录,次日交会议秘书处打印。风暴酝酿在讨论林讲话的过程中。

文化大革命沉思之五十二

林讲话对张春桥是震慑但未指名,经过叶群警示“陆定一式人物”的传话,陈、吴、李、邱在小组发言中暗示有人反毛林,反八届十一中决议,反毛是天才并把这股风往下吹。华北组汪东兴一马当先,坚决主张恢复国家主席设置,暗示有人反毛,称“这是没有刘少奇的刘少奇路线,是刘少奇反动路线的代理人”。陈伯达讲有人贬低毛思想,有人怀疑八届十一中全会公报。汪、陈的发言作为华北组第二号简报印发全会,简报称要把反毛天才的坏蛋反革命揪出来示众批倒批臭千刀万剐。这个简报点燃了过敏的政治神经。二百多与会者纷纷发言写信,要求揪出“党内的大坏蛋”,揪出“毛主席身边的野心家、阴谋家”,邓颖超说:“谁反对林副主席,我们就打倒谁。” 汪东兴说:“现在是笔杆子压枪杆子”。许世友说:“造反、造反,你们造谁的反?”许世友、杨得志、韩先楚致信毛林,要求毛当国家主席。许提议把张春桥等下放农村劳改三年。陈云说:“林副主席号召我们起来战斗,这种战斗一定要参加。”陈毅说:“九大之后,我是被打在阴沟里的,现在我必须爬出来,跟着林副主席一起战斗。”……林的讲话,经叶群的引导,陈、汪的解释发挥,变成二百多中共要员讨伐张江的动员令,达到了清君侧的策略效应,对毛重用张甚至培养其为接班人是一种中流阻击,曲折地表达了文革中受冲击打压的老干部对中央文革的愤怒与敌视。

文化大革命沉思之五十三

毛林国家主席之争是烟幕,捍卫还是动摇接班人地位才是本质,两班人马、两个阵营,较文革初更加壁垒分明。如果说,文革发动前后的两个司令部是毛亲手划定,那么,庐山博击的文革派与军队派则更似运动形成。而林,更似是被毛刺激出洞,如高文谦所言为捍卫九大确立的接班人地位与受屈的个人尊严以惯用的高举造神方式奋力清君侧,其忠实嫡系(双红二)紧紧追随,四面出击,多方响应,大笔杆子陈伯达与近卫军总头领汪东兴做了“突然袭击煽风点火唯恐天下不乱”的急先锋,意外地把大多数文革中蒙冤受屈被边缘的元勋重臣都动员起来集体在拥护林副主席的名义下起哄,实为发泄对张江的中央文革势力的不滿,以改变毛的偏宠。陈伯达因嫉恨张江而主动为林出谋划策全力配合以夺回其党内首席理论家的席位。汪在九大到九届二中全会的怪异表演实为可疑,检查后一如既往为毛信用也不寻常,值得专门探究。黄吴叶李邱作为反张江的林系人员罕有的联合互动在共产党的高层政治生活中亦是不常见的,“党内有派”?双方互指对方有宗派活动,在毛的旗帜下如地方两派一样明争暗斗,这是四年文革后党内出现的新气象。文革前的刘邓时代似无明显的派系活动。由此而言,文革开始蕴育其掘墓人。

文化大革命沉思之五十四

8月25日,毛听了江张姚会议讨论情况的紧急汇报,立即找汪谈话,对其告诫,又分別与林周陈康单独谈话,迅雷不及掩耳反击,召集常委扩大会,怒斥陈伯达搞突然袭击,声称“我毛泽东是不当国家主席了,要当,你陈伯达去当好了。”以其惯用的泼皮语言警告不要开成“分裂失败的会议”。毛决定立即停止讨论林讲话,收回华北组第二号简报,责令陈吴汪等检查。林告吴不必检讨。局势骤变。毛抓住陈伯达不放,26日严厉批陈,31日批陈所编恩列毛天才语录,其中有“我跟陈伯达这位天才理论家之间,共事三十多年,在一些重大问题上就从来没有配合过更不去说很好的配合”诛心之语,讽刺陈为“天才理论家”,对林笼络,专门攻陈。并于9月1日将批陈批语加题目“我的一点意见”印发全会。9月4日,毛在常委扩大会上揭发陈是“托派、叛徒”,追随王明反共。9月6日,毛在闭幕会上讲要读马列,指陈为“黑秀才”,决定对陈立案审查。毛委托叶剑英具体负责陈案,调查陈的历史问题。毛“剪相侧”一举成功。毛保张,因为张体现了他的意图,是坚定的文革派造反派。文革后宋平说,毛是最大的造反派。庐山雾散,服务员打扫会场时,检到“打倒张春桥一一几个中央委员”的纸条送周。林下山时对黄吴李邱说,不做亏心事,不怕鬼叫门……最多是彭德怀第二。 庐山的事未了。

文化大革命沉思之五十五

庐山会后,毛继续批陈,在北京对陈先瑞、吴德说:“陈伯达是船上的老鼠,看见这条船要沉了,就跑到那条船上去了。”毛把自己与林比作对立的两条船,名为批陈,实为对林。毛把汪检讨的批件批给林,要黄吴李邱书面检讨,并决定在全党全军开展批陈整风,称陈为“刘少奇一类政治骗子”。70年9月,毛决定董必武朱德叶剑英参加重大政策研究。11月,毛决定设中央组织宣传组,组长康生,组员江张姚纪登奎李德生,康自九届二中全会后称病不出,江张主持,该组权力集中广泛,统管组织宣传党校等党务。与军委办事组、国务院业务组鼎足而立。70年底华北会议毛改组北京军区。毛指陈为华北的太上皇,免去了李雪峰、郑维山的职务,任命李德生、谢富治、纪登奎为北京军区司令员、政委,毛称为挖林的墙角,其中李郑与林陈无特殊关系。71年2月,毛远新亮相,指“庐山问题的实质是未遂的政变”。俨然毛的代言人。71年4月,毛派纪登奎张才千参加军委办事组,后称为“掺沙子”。对吴、叶的检查,毛加入尖刻的批语,冷嘲热讽,旁敲测击,如在叶群检讨上批“爱吹不爱批,爱听小道消息,经不起风浪”,后来又说:“不要把自己的老婆当自己工作单位的办公室主任、秘书。林彪同志那里,是叶群同志当办公室主任。”令林难堪,意在逼林检讨。林沉默以对,死不检讨,为毛时代的又一个异数。因为林深知刘、彭的结局,检讨了也是死路一条,反而被毛抓住把柄,自取其辱。前有林彪,后有赵紫阳,都是中共高层不检讨不认错的异类。

文化大革命沉思之五十六

庐山会议甫过,毛通过一系列密集的人事调整与批陈政治造势,改变九大的组织格局,削弱林黄掌控的部门与权威,以批陈不力屡批黄吴叶李邱,并在对外谈话与批示中指责林对毛的颂词,如四个伟大,这些颂词曾是毛发动文革时乐于纳受而且认为有必要的。到71年4月,周代表毛宣布黄吴叶李犯了方向路线宗派主义错误,追随陈伯达的分裂路线。党内七大以后惯例,凡不同于毛者为分裂。毛怎样违背众意都是反潮流的正确路线。批陈实质上是批林。对林的进逼在8月南巡中图穷匕现。毛说:陈伯达后面还有人,“黑手不只陈伯达一个,还有黑手”。林不开口,黄吴李邱不会开口的,其纲领是设国家主席,是天才,林要负责任,有人急于想当国家主席,急于夺权。“1959年庐山会议跟彭德怀的斗争,是两个司令部的斗争。跟刘少奇的斗争,也是两个司令部的斗争。这次庐山会议,又是两个司令部的斗争”。犯了路线方向错误,为首的,改也难。南巡讲话毛把林看作彭、刘。林获悉毛南巡讲话后,不甘于刘、彭下场,小杖则受,大杖则走,9月13日携叶群林立果乘空军256专机出逃苏蒙,坠亡于蒙古国溫都尔汗。九十年代我翻过一册军方刊印的十大元帅画册,最后一幅是一代战将折戟沉沙尸横异域的照片,心生凄恻。

文化大革命沉思之五十七

林彪被逼出走苏蒙的九一三事件举世惊骇,对文革期间高度政治化的党政军民学是天降霹雳,长久地震荡着人们的灵魂,确是灵魂深处爆发革命,再愚钝的头脑也开始思考文革的问题。文革的凯旋仅仅两年,九大确立的接班人成为反毛的政变领袖。关于林彪出走的疑惑甚多,传闻甚多,李作鹏甚至讲是故意放走的。这不是本文关注的重点。9月29日,毛决定收捕黄吴李邱,军委日常工作由叶主持。随后撤销军委办事组,成立军委办公会议。10月3日,决定成立周恩来负责的林陈反党集团的中央专案组,纪登奎汪东兴具体负责。林案被定为组织谋杀毛的反革命武装政变。这是中共建政以来定性最严重的案件。疏理审核公开公布的全部文件,林叶黄吴李邱无确凿证据证明参与了谋刺毛的行动,有无谋刺计划亦不可知。据传黄曾封锁毛批陈指示,念过一首唐诗:“竹帛烟销帝业虚,关河空锁祖龙居,坑灰未冷山东乱,刘项原来不读书”。林立果的所谓小舰队确有批毛害毛的私下议论与设想,但似未有实际作为,也无周密计划,其价值最大的,是被毛钦定为反革命政变纲领的《“571工程”纪要》,这是一份难得的思想文献。李慎之生前对我讲,对毛的批判迄今未超过纪要。

文化大革命沉思之五十八

“571工程”纪要是在北京空军学院林立果等人活动的一座小楼里搜到的于新野记录在活页纸上的林立果周宇弛等人的桌边谈话,这些记录估计非一次两次,而是多次谈话的笔记。据说是九届二中全会后形成的。林彪事件后,林案的相关人员对这些记录作了选择性整理,作为林彪的罪状和林彪的反革命纲要,毛决定将其印发各大军区和各省委常委,后作为《粉碎林陈反党集团反革命政变的斗争(材料之二)》的附件印发全党,以说服全党和全国人民充分认识林彪反毛的两面派本质。没有证据表明林彪参与或知道这个纪要,更无黄吴李邱知道这个纪要的确切证据。合理的推测是,纪要是以林立果为中心的调研小组自由讨论的记录,反映了他们这些青年军官的政治分析与思想动态,也包括一些救弊治国的一些主张。其中是否有林彪思想的影响,难以断定。如果说,毛刘之争还声势浩大地批判了几年“黑六论”,有理论论争的意味,但毛林之争毛公之众的是林的阴谋诡计,如利用设国家主席和称天才抢班夺权,及叛国卖国云云,后来周批“空洞极端形式主义”极左思潮,为毛扼制,指林形左实右,“极右,修正主义,分裂,阴谋诡计,叛党叛国”……那么,这份林立果思想的纪要却有了特殊价值,迄今仍是一份珍贵的政治思想文献。

文化大革命沉思之五十九

那么,林立果的纪要是如何看待与评估毛时代的社会状況呢?纪要称:“十多年,国民经济停滞不前”。十多年,应从58年算起。据统计,66一68年因文革内战导致国民经济损失1100亿。纪要称,经济停滞的后果,“群众和基层干部、部队中下干部实际生活水平下降,不满情绪日益增长”。纪要对各阶层的状况与不满情绪言简意赅:“农民生活缺吃少穿”,“工人(特别是青年工人)工资冻结,等于变相受剥削”,城市学生构成的“红卫兵初期受骗被利用,已经发现充当炮灰,后期被压制变成了替罪羔羊”,“青年知识分子上山下乡,等于变相劳改”,“机关干部被精简,上五七干校等于变相失业”,“党内长期斗争和文化大革命中被排斥和打击的高级干部敢怒不敢言”,……从农村到城市,从农、工到学生、干部,林立果描述的这幅文革社会各阶层的惨淡画面是八九不离十的。纪要称,“统治集团内部上层很腐败、昏庸无能”、“统治集团内部很不稳定,争权夺利、勾心斗角、几乎白热化”,张姚一“小撮秀才仗势横行霸道,四面树敌,头脑发胀,对自己估计过高”。结论:“独裁者越来越不得人心”。

文化大革命沉思之六十

林立果纪要中的独裁者指毛泽东,代称B一52。纪要称毛是“执秦始皇之法的中国历史上最大的封建暴君”。纪要揭露了毛之为毛的政治手段:“今天利用这个打击那个,明天利用那个打击这个。今天一小撮,明天一小撮,加起来就是一大批”,“利用封建帝王的统治权术,不仅挑动干部斗干部,群众斗群众,而且挑动军队斗军队、党员斗党员,是中国武斗的最大倡导者。”纪要列举毛的罪状和众叛亲离,称“从几十年的历史看,究竟有哪一个人开始被他捧起来的人,不被到后来不曾被判处政治上死刑?有哪一股政治力量能与他共事始终。他过去的秘书,自杀的自杀,关押的关押,他为数不多的亲密战友和身边亲信也被他关进大牢,甚至连他的亲身儿子也被他逼疯”。纪要抨击了毛的权谋政治,称“他是一个怀疑狂、虐待狂,他的整人哲学是一不做、二不休。他每整一个人都要把这个人置于死地而方休,一旦得罪就得罪到底、而且把全部坏事嫁祸于別人”。有人怀疑这些深刻的观察非林立果几个青年人所发明,那么,纪要是否与林彪有关呢?林立果这样一个年仅25岁的理工男如何具备这样一针见血的判断呢?纪要不就是一篇七十年代始林立果对毛时代政治与社会的反思吗?

文化大革命反思之六十一
因为是小团体的“特级绝密”,纪要对毛与毛时代的批判是赤裸裸的坦率,无忌无讳。思想理论上,纪要称毛的“笔杆子托派集团正在任意篡改歪曲马列主义,为他们私利服务”、“他们用假革命的词藻代替马列主义,用来欺骗和蒙蔽中国人民的思想”,“他们的继续革命论实质上是托洛茨基的不断革命论”,在社会政治领域,毛“把党内和国家政治生活变成封建专制独裁式家长制生活”,“把中国的国家机器变成一种互相残杀、互相倾轧的绞肉机式的”,其“社会主义实质上是社会法西斯主义”,其革命对象实际是中国人民,而首当其冲的是军队和与他们持不同意见的人“。纪要推测毛好景不长,”急不可待地要在近几年内安排后事“。林的接班人地位汲汲可危,那么,怎么办呢?纪要设计以活捉、逼宫或谋杀方式倒毛,动员口号是”打倒当代的秦始皇“、”推翻挂着社会主义招牌的封建王朝“,对过去毛以莫须有罪名加以迫害的人,一律政治上平反,实现民富国强,使人民丰衣足食,安居乐业。纪要在提出打着毛的旗号打击毛的力量时,强调集中打击毛及其一小撮独裁者,解放一大片。可以想见,对于文革中沉醉于毛的迷信的党群众生,林立果的讨毛檄文是多么石破天惊,是二十世纪七十年代的骆宾王讨武奇文。请看今日之域中,竟是谁家之天下!

文化大革命沉思之六十二

林案定罪最为严重,甚于张国焘,林彪作为九大确立并写入党章的领袖接班人被中央专案组定为”资产阶级野心家、阴谋家、反革命两面派、叛徒、卖国贼“永远开除出党,牵及包括林在内九大选出的两名常委,七名政治局委员(陈黄吴李邱李被永远开除出党),为九大政治局委员的三分之一。四野及双红二的林部属被反复审查,株连甚广,其对军队清洗程度为七大以来最烈,即使文革结束后,因华叶邓陈决定维持林案不变,林案的受屈人员仍然依旧。邱会作说,把林江綁在一起审判,实际上就是审判毛的九大政治局。此言不虚。林彪事件有多重的意义。意识形态而言,毛圈定林的政治纲领是设国家主席、理论纲领是称天才,不足以服人,更不足以为高层心服,人们实在不晓得毛林的政治分歧是什么?对于毛津津乐道的”路线斗争“,人们普遍地感到”不可知“。难道林彪的罪恶是鼓吹对毛的个人崇拜?这是毛迴避的问题。组织而言,毛遵义会议以后长期依重的军队嫡系受到重创。毛最敏感党内军内结伙,却是他曾最亲密的战友们结伙反他的老婆和他的新宠张春桥,动摇他的文革路线,甚至亲密战友的儿子组建了一个谋杀他的小舰队……对于毛,这是讽刺,是嘲弄,是延安以來极为自傲的政治生涯的重挫与低谷,比七千人大会时还被动,71年10月,毛对塞拉西皇帝说:“早几个星期前,我因为心脏病已经死了一次,上天去了,见了一次上帝”。毛的心理与生理进入了衰退与衰亡的最后时期。

文化大革命沉思之六十三

林彪事件之后,毛昏死过两次。政治局中江青、周恩来的地位突显出来。林立果观察得很准,毛“要在近几年内安排后事”。在讲毛谋划新权力格局之前,72年发生的一件大事值得评估,就是中国进联合国和中美关系正常化,后一件事是周鼎力協助毛晚年为中国未来铺垫的至关重要的事件,为后来邓小平的开放打破了坚冰。尼克松访华起因于中苏珍宝岛战役引起的苏联对中国的核威協和美对苏的核制衡,而中国又因缓和中美关系而成为美在国际范围内制衡苏联促进美苏缓和以裁军的因素。“中美两国关系走向正常化是符合所有国家的利益的”。毛的“联美反苏”的外交政策转变打开了一个面向世界文明的窗口。封闭的中国开始走向世界。二十余年狂热的反美意识形态骤然降温,交流取代了对抗。因此,中美关系正常化对中国以至世界的命运都有举足轻重的影响。尼克松访华的一周“对中国今后的道路真正是旋乾转坤的一周”。正如李慎之所言:“在1981年6月十一届六中全会通过的《关于建国以來党的若干历史问题的决议》中,对于毛泽东时代的外交政策没有一个字的批评,原因就在于毛泽东晚年做出了改善中美关系的决策。实际上,全党可以没有遗憾地接受的毛泽东的遗产也仅仅是这一点,虽然是极其重要的一点。”毛转移国内危机的战争冒险结出了中美交流的善果,应是天佑中华。

文化大革命沉思之六十四

林彪的出走与林案破了毛苦心经营半个多世纪的革命大局,对毛的精神与身体都是无法复原的重击。副统帅的鬼魂徘徊不去,恶梦连连,寝食难安,摔杯砸碗,脾气更加坏下去。孤独而虚弱,定时借人工氧气存活的毛首先考虑的是他的千秋大业一一文革,对毛来说,路线的根基是组织人事,离开权力,一切都是空谈。文革七年,还是一个接班人问题,谁来接班?鹿死谁手?72年,毛调派王洪文、邓小平、华国锋进京,加上此前入主军机的张春桥、李德生,五雄争帅,城头变幻二王旗。毛最先属意的接班人是天字第一号造反派王洪文。73年5月,毛决定王洪文、华国锋列席政治局,王列席三个会议(中央政治局、国务院、中央军委),负责党章修改小组。8月,毛建议王任中共十大选举委员会主任,周为副手。十大,周的政治报告充分肯定文革并把推倒林陈当作文革又一伟大成果,王代表中央作《关于修改党章的报告》,将“还要进行多次象无产阶级文化大革命这样的政治大革命”增写进党章,晋升中央副主席,年仅三十八岁。张春桥进常委,江青、姚文元进政治局。林彪走了,王洪文来了。王是文革造反夺权的符号,造反英雄终成接班人,十大是造反派胜利的代表大会。

文化大革命沉思之六十五

林彪事件后,周曾伏案痛哭,似乎预感将在迟暮之年更为困厄艰辛。他负担更重,压力更大,也由党内第三号人物升为第二号人物,与毛的关系更为直接敏感,伴君如虎。72年,废除军管,恢复地方党委。对于批林,周小心翼翼导向批左与无政府主义,批空头政治,以落实干部政策和恢复经济、文化、教育的正常秩序,放宽农村经济政策,收拾文革乱局。“批透极左思潮”成为周在72年的一面旗帜,周指出,极左思潮就是夸夸其谈,空洞、极端、形式主义,空喊无产阶级政治挂帅,而于实际操作,周借毛参加陈毅追悼会与平反贺龙及曾山、陈正人之死,推动更多老干部复出。周之资望、信誉与凝聚力时为国之柱石、党之干城。江、张、姚以“反右倾回潮”回击周,因极左与文革水乳交融,批左就是批文革,毛支持江张制止周反极左,讲批左把批林批邪了,而指示批林“极右实质”,禁止批左、批唯意志论、批精神万能论与空头政治论,并将批林导向批孔,指向周的中庸之道。毛写了一首流行甚广的诗批郭沫若尊孔:郭老从柳退,不及柳宗元。名曰共产党,崇拜孔二先。指责郭《十批判书》的人本主义,即人民本位主义。73年9月,毛说:“林彪骂我是秦始皇……我赞成秦始皇,不赞成孔夫子”。那么,批孔又为何与批林联系起来了呢?又怎样与批周联系起来了呢?

文化大革命沉思之六十六

批林整风时,林案人员迟群谢静宜等在林彪官邸毛家湾搜查时发现林彪称道孔孟的若干语录,毛决定批孔。74年,毛将江青定稿的《林彪与孔孟之道》的材料选编以中央文件批发全党,把林彪反毛的思想归因于尊孔反法。林彪曾写条幅并赠叶群:悠悠万事 唯此为大 克己复礼。林讲的复礼究竟为何义,不得而知,毛江张姚讲林是复辟资本主义。林彪给林立果写了“学习韦编三绝的治学精神”,以激励其子勤奋读书,被批判为宣扬孔孟之道。林彪60年讲“两斗皆仇,两和皆友”,被批判为孔子“礼之用,和为贵”,右倾投降,复辟周礼。69年林彪书写“王者莫高周文”,推崇周文王,被批判为做皇帝梦。林彪引了孔子“志士仁人,无求生以害人,有杀身以成仁”,被批为崇尚蒋介石。林彪抄录了《三国演义》一首诗“勉从虎穴暂栖身,说破英雄惊煞人,巧借闻雷来掩饰,随机应变信如神”,被姚说成林睡在毛身边谋害毛,耍两面派……批孔之荒诞,荒诞派剧作家也望尘莫及,其恶果是对中国文化的毀灭。批林之荒唐,民众对毛江路线斗争之指鹿为马完全失去兴趣,政治激情转为冷漠,更加关注日常的烦恼,更为好奇中南海的秘闻。所以,江青的批走后门倒是引起了人们对特权的抨击和生存困境的不满,文革时期的权本位在整人与走后门中渗透到一切单位一切领域。

文化大革命沉思之六十七

毛是终生的反孔派。以斗争为生命。文革中宣称两个决裂,全盘否定传统文化。早在66年底,毛讲过文革的一个基本任务是清除孔儒的影响。秦始皇也是毛心仪的历史人物。“秦皇汉武”。但林彪事件深深刺激了毛,因为林家父子诅咒毛为当代秦始皇,令毛耿耿于怀。73年毛给郭的诗:劝君少骂秦始皇 焚坑事业要商量 祖龙魂死秦犹在 孔学名高实秕糠 百代都行秦政法 十批不是好文章 熟读唐人《封建论》 莫从子厚返文王 抒发了这种郁闷的情绪。 而林彪是崇文王的。毛说,郭老对待秦始皇,对待孔子的态度和林贼一样。因此,发动批孔运动,是批古人死人以警示活人,如张江姚所暗示的现代的儒,党内大儒。74年1月25日批林批孔动员大会上迟群谢静宜批“折衷主义”、“中庸之道”,称“凡是主张中庸之道的人,其实是很毒辣的”。矛头所指是人所尽知的。江批评周对批孔“行动迟缓,跟不上形势”。对批孔的真实想法,周曾对其侄说:“对孔孟之道还是要进行全面地合理地科学地研究分析”。江还利用批林批孔不断染指军队。显然,毛亲自发动和领导批孔运动是为了防范周对文革“右倾翻案”。影射史学是这一时期官方意识形态的独特特征。“周公”成了周恩来的暗喻。另外,权衡利弊,毛重新启用邓也是制周甚至代周。

文化大革命沉思之六十八

维护文革的历史地位与收拾文革的动荡混乱是毛垂暮之年政治上的指导方针。这是毛最后的战争。邓二次出山是毛的一步险棋。毛一直保留邓这个棋子以观后效。72年8月,毛在邓信上的批语主要讲邓在中共建政前的功劳。对于中共建政后,毛只讲邓“进城以后,也不是一件好事都沒有做的,例如率领代表团到莫斯科谈判,他没有屈服于苏修”。据相关学者研究,49年之后,特別56一61年,毛邓有一段非常密切的合作时期,被评为“谋事在毛,成事在邓”。56年八大以后,邓以总书记主持党政军日常事务,号令八方。毛在59年确实讲过,他是正帅,邓是副帅,“权力集中在常委和书记处”,以至贺龙问朱,少奇怎么摆?只是62年大饥荒以后,毛邓政见有別,渐行渐远,毛讲邓总躲着他,“敬鬼神而远之”。文革时毛几次讲邓是刘司令部中摇鹅羽毛扇的军师。应该说,大饥荒与谪居江西的两个三年是邓反省左祸的两个关键性觉悟时期。九大以后政局的诡异突变,远放江西的邓又有了出头的机遇。73年3月,邓复出任国务院副总理,列席政治局会议。王洪文将如慧星流过,轮到“党内二号走资派”登场了。

文化大革命沉思之六十九

毛对邓的任用与考察近两年,从73年3月邓孤独地现身于国务院招待西哈努克的宴会,其国内的落寞与海外的轰动意味深长,到因周遭遇十一月寒流而崛起于政坛,才为邓的施政结束了预备期。周被毛视为老右,林倒后,毛的目光聚焦于周,而周在政坛的地位与影响无与伦比,海内外瞩望,一人之下,亿众景仰。74年国庆招待会,周短短祝酒词被十余次掌声打断,人心向周而非毛。江张姚的前哨骚扰接连不断,而终于在周与临別的基辛格会谈军事合作问题未及时请示毛而决定继续交换意见的所谓外交失误上引发惊涛骇浪,毛严厉指控周接受美国的核保护伞,苏联打过来要当儿皇帝,11月21日到12月上旬,政治局会议连续批判周叶的右倾投降的修正主义路线,周奉旨主持自己的批判会,江指责周是“错误路线的头子”,迫不及待取代毛。周对江申辩:我周恩来一辈子犯过很多错误,可是右倾投降主义的帽子扣不到我的头上。政治局会开成了对周的批斗会。这是74年江青策动批林批孔批周公及“揪现代大儒”的政治背景。邓冷静观察,体悟圣心,会议结束前对周警示:你现在的位置离主席只有一步之遥,別人都是可望而不可即,而你却是“可望而可即”。话不多而言重。毛知后随即决定邓进政治局、军委,任总参谋长。称“请了一个军师”。

文化大革命沉思之七十

“一朝权在手,便把令来行”。邓顺应当时民众厌乱望治的普遍心理,以举重若轻的强势作派开始了清理文革的全面整顿,被杨小凯称为英国革命蒙克将军的复辟。邓不是周,是急性子,且在南昌效野的小路上走了三年,沉思了三年,不说急不可待,亦是跃跃欲试。邓出山是一个标志,老干部越来越多恢复原职,还乡团回来了。毛把二月逆流以及贺龙杨余傅罗瑞卿等案的责任统统推给死无对证的林彪,高层的政治气氛大大和缓,为了支持邓放胆工作,毛建议邓出席联大特別会议,批评上海帮、四人帮,并称江青“并不代表我,她代表她自己”。4月,邓在联大上发言:“如果中国有朝一日变了颜色,变成一个超级大国,也在世界上称王称霸……那么,世界人民……就应该揭露它,反对它,并且同中国人民一道,打倒它”。10月, 江张等籍风庆轮事件攻击国务院“崇洋媚外”,邓在政治局会议上以理力争,江大吵大闹,邓拂袖而去。在四届人大筹备期间,毛决定周与王共同负责,并建议邓任第一副总理兼总参谋长,张春桥任总政治部主任。12月,毛又决定邓任中共中央副主席、中央军委副主席。邓羽毛丰滿。75年将是邓小平“全面整顿”的一年,正是这一年的作为与成绩及由此享有的声望,为改革开放时期邓的核心地位奠定了基础。

文化大革命沉思之七十一

批孔的一段插曲 冯友兰《论孔丘》发表后,梁漱溟在政協学习组对批孔运动始终保持沉默。他对把林彪的所作所为归罪于孔孟之道不以为然。政協的同事们劝告梁向冯氏学习,公开发表意见支持批孔,梁说,冯文讲得未必是真话。梁被围攻,要求他对当前批孔运动明确立场,端正态度。梁说,我对当前的“批林批孔”运动持保留态度。至于如何评价孔子,我有话要说……主持会议的人要梁讲讲,长短不限。74年2月22日,八十一岁的梁登台开讲:今天我们应当如何评价孔子……绝对的肯定或绝对的否定,都是不对的……孔子本人已不会说话,不会申诉,大权操在我们手里,由我们来判断。……我的看法是,中国有五千年的文化,孔子是接受了古代文化,又影响着他之后的中国文化的。这种影响,中国历史上的任何一个古人都不能与孔子相比。……所谓“极高明而道中庸”,要深入加以研究,这是学问很深的学术问题……梁氏的讲演在当时只是鸡同鸭讲,只能招致一阵疯狂的大批判。面对轮番的批判质问,梁氏答云:三军可夺帅也,匹夫不可夺志。 最后的儒家一一梁氏的独立思考与自由思想是永远值得纪念的。

文化大革命沉思之七十二

74年11月,受毛委托,邓为病重的周主持起草了最简洁的在四届人大上的政府工作报告,控制在五千字以内,主旨是国民经济的发展和在本世纪实现四个现代化。现代化,经过文革八年的折腾,经过周邓务实派的顽强努力,又回到国家的正式议程,成为主导中国未来四十余年的奋斗目标。这是举国举世注目的大事。75年1月,周以病弱之躯念了开头的这个报告转瞬间为迷乱动荡的国人开了一扇面向未来的窗口。然而,四届人大的现代化,仍限于工业、经济与技术的现代化,这个目标经过三十余年改革开放的努力,已基本实现了。而政治、社会与文化的现代化一一法治、公民社会与宪政民主一一本应成为未来中国三十年的奋斗目标,以成就四化的初衷乃至中国仁人志士百年来的梦想,这是现在富裕起来的中国人的真实利益与渴望,也是现代中国唯一正确的选择。遗憾的是,执政党却沒有把这样的目标一一国家制度的现代化一一中华民族复兴的真正希望作为国家的议程、国家发展的方向,凝聚中国民众的共识,以制度变革的智慧解决改革开放过程中的问题与失误,让人权的普世价值照彻通向世界文明的正途。

文化大革命沉思之七十三

四届人大甫过,周宣布邓主持国务院工作。早在73年4月,周在玉泉山与邓长谈,通报张春桥是叛徒,主席不让查。邓与周就达成了政治默契。5月,邓主持中央工作。邓接手的中国政局,问题成堆,吃饭仍是很大的问题,魚米之乡的浙江,要从北方省份运地瓜干、小麦救灾,运输的火车车厢上写着白漆狂草“给浙江懒汉吃”,金华、溫州发生了民兵参与的大规模武斗,伤亡惨重,省委书记谭启龙被绑架。……邓的全面整顿先从军队开刀。文革把中国折腾成军政,军队膨胀,从59到71年,军队总人数增加360万,74年时,军队干部超编60多万,多为非作战部队的政工闲杂人等。文革派性渗透军队,纪律散漫,训练废弛,有令不行,74年西沙作战时,有擅自把大队长以上干部派去执行临时任务。准备打仗,是邓整顿军队的纲。邓以“肿、散、骄、奢、惰”概括军队痼疾,消肿为首,重点清除派性,并严防中央文革势力控制军权。叶警告,不容许任何野心家插手军队。叶与各军区各军种负责首长以个別谈话的方式,通报毛对上海帮的批评,对任何人不经过军委干预部队事务的,有权抵制。75年6、7月军委扩大会议后,组建了叶聂粟陈杨成武梁必业的军委领导小组,决定减少军队定额160万,其中主要削減机关、后勤与陆军,加强海空军与特种兵,保留技术骨干,选配与调整军队的各级主官。

文化大革命沉思之七十四

邓力推的全面整顿,集中触动了文革后期国民经济与社会政治积压的各类棘手问题,如体制机制、管理规章、派性、条条块块、军队地方、冤假错案等,在毛坚守文革基本格局与意识形态进攻性的限制下,处理这些尖锐顽症,必然触及文革,难免遇到巨大的干扰与阻力。尽管中共领导阶层劫余所存,千疮百孔,仍在各重要领域有一批有识有胆有能有为且敢于为民先驱的猛将,如铁路交通领域的万里,科技领域的胡耀邦,教育领域的周荣鑫,国防工业领域的张爱萍,财政领域的张劲夫以及国务院研究室的胡乔木、于光远、邓力群,邓在党政军的主要助手,如叶剑英、谷牧,地方才俊赵紫阳等,没有这些人的鼎力推进与冲锋陷阵,邓小平是孤掌难鸣的。而邓的气势作风,亦可圈可点。如对军队派性,邓讲闹派性的一个不留,万里讲徐州受冤平反者应有七八千人之众,邓讲要借东风一块解决,七八千人,800人一批,分10批,公开向群众宣布。平反要一批一批地搞。邓籍整党在全国范围内清洗新老造反派及反潮流分子,削弱中央文革势力的干部基础。邓否定了胡乔木政研室吸收一些革命造反派的建议。对邓而言,四化、现代化是大局。三个文件的起草一一《关于加快工业发展的若干问题》、《科学院工作汇报提纲》和《论全党全国各项工作的总纲》,为全面整顿提供了理论根据,既是六十年代初各种条例的承继,又是八十年代改革的先声。1975年,是十年文革中较有生气的一年。

文化大革命沉思之七十五

毛在从战术上起用邓治理整顿的同时,从未忘记巩固文革的既定方针。毛重用张春桥,从意识形态方面为文革护法。74年底,毛关于专政理论的谈话,就是为文革寻求马列理论的依据,其实质内容是限制资产阶级法权,即商品制度、工资制度、按劳分配、货币交换,强化无产阶级专政,构建系统的继续革命理论,建立传之千秋万世的文革道统,也为邓的整顿划一个界限。文革的理论是这一时期形成的。首席理论家是张春桥。张在四届人大上做修改宪法的报告,把五四宪法修改成全面专政的阶级斗争宪法,可取之处是准许罢工自由。随后,张被毛任用为总政治部主任。李德生因与江青冲突被贬为沈阳军区司令员。张如愿以偿介入军委领导核心层。75年2月,毛决定印发张姚摘编的《马克思、恩格斯、列宁论无产阶级专政》语录二十三条。4月,张春桥发表了杀气腾腾的《论对资产阶级全面专政》,称文革的实践证实了文革的理论。张春桥称:“一个官僚资本或民族资本的企业,怎样变成社会主义企业的呢?还不是我们派了一个军管代表或者公方代表到那里,按照党的路线和政策加以改造?”张强调政治领导权是最根本的,只要有权,所有制想变就变。而文革解决的就是领导权问题。乌有之乡的文革鼓噪不过是张春桥思想的拙劣的复制。

文化大革命沉思之七十六

毛的两手政略引起文革派与整顿派的不断冲突。两派难以调和。为癌症所苦的周在垂死之年为邓保驾护航。应该说,是这个时期,也只是在这个时期,周邓的政治命运才牢牢地并为后世永久地连在一起了。75年4-6月张王江姚反经验主义为邓叶周通过毛联手扼制,邓叶还借此对江青严加批评,江做了书面检讨,检讨了四人帮的宗派主义。75年8月,毛评论《水浒传》:”《水浒》这部书,好就好在投降。做反面教材,使人民都知道投降派。《水浒》只反贪官,不反皇帝。屏晁盖于一百零八人之外。宋江投降,搞修正主义,把晁的聚义厅改为忠义堂,让人招安了。”谁是投降派?谁是宋江?谁是晁盖?姚将毛的《水浒》评论起草了一份反投降派与投降主义的请示报告,其核心观点为修正主义者都是投降派。毛批发全党,掀起了一个评《水浒》的奇异的政治运动,江青称:评论《水浒》的要害是架空晁盖,现在党内有人架空毛主席。显然是把矛头指向周邓叶的。毛或许有被老战友们孤立之感,自比晁盖,那么宋江一定是周。被谁招安呢?美国吗?周病魔缠身,心地苍凉,对老朋友蔡畅说”我周恩来决不是投降派”。9月,周对邓说,你这一年干得很好,比我强得多!周自知不久于人世,遂亲笔致信毛举荐邓接替他现任的职务。此信石沉大海。而毛,越来越难以容忍邓纠正文革的后果,邓亦不妥协,周于是在批邓的压力下,在越剧《黛玉葬花》的忧伤曲调中,绝望地辞别人寰。周的一生是悲剧的一生。

文化大革命沉思之七十七

批邓反击右倾翻案风是毛发动的最后一场政治运动,是运动一生的共产袅雄在垂死之年对”资本主义”风车的最后一击。本来是幻影的风车不但没有消失,而且无中生有,越转越大。这是历史的喜剧。证实了超级的权力意志在时代趋势与人性顺逆的伟大力量前面是何等的渺小何等的卑微!75年10月,毛留其侄毛远新做自己与政治局的联络员。毛要小毛帮助江。文革的政治是毛江的政治。反对江青的元老勋臣在毛手下迟早都受到残酷的斗争与无情的打击,只有周体悟这个政治秘密。周曾告诫邱会作”中央政治就是处理好主席、林副主席、江青的关系”。林副主席死了,中央政治就只有毛与江了。细细品味毛对江的多次批评,关爱之情绵绵不绝。十大会后,毛见吴德等,谆谆教诲他们支持江张王姚,如培育花园的春苗。小毛与江青心有灵犀相互支持。王海容唐闻生因受康生嘱托调查江青叛徒历史而被毛疏远。章含之为此事向江青的告密令其夫乔冠华晚岁坷坎郁郁而终。而邓,是又一个钢铁公司,绵里藏针,是从来不把江青看在眼里的。毛曾要江找邓沟通,江邓话不投机,不欢而散。邓是不可能辅佐江的。这不符合邓的政治性格。

文化大革命沉思之七十八

毛远新进京入中枢随侍核心左右,政局很快逆转。毛从不同渠道包括李先念获知邓在全面整顿中对文革的非议,其中小毛的汇报有不可低估的刺激因素。早在9月27日,小毛向毛反映社会上有股否定文革的风。当毛联络员后的11月2日,小毛对老毛说:对文化大革命,有一股风,似乎比1972年批极左而否定文化大革命时还要凶些。担心中央,怕出反复。我很注意小平同志的讲话,我感到一个问题,他很少讲文化大革命的成绩,很少提刘少奇的修正主义路线。”三项指示为纲”,其实只剩下一项指示,即生产上去了。 应该说,小毛的观察并不错,邓确是以四届人大宣告的四个现代化为政治大局与指导方针推进全面整顿的,对文革造成的派性混乱坚决处置,必欲除之而后快,否则就不会有什么安定团结与现代化。也正是这种拨乱反正的努力,经济社会局面有了好转。邓的黄金岁月一年有余。但毛,对于文革的任何批评都是高度敏感与高度警觉的。文革是毛的禁地与禁忌。老毛赞成小毛的看法,讲有人要算文革的帐,委托小毛开小会解决邓的文革立场问题,冲突箭在弦上。

文化大革命沉思之七十九

批邓肇始于邓两次转送清华刘冰信给毛,刘信反映的是迟谢私人品行的不雅与迟的迷权逐势等不良表现,毛勃然动怒,批评刘信动机不纯,”是想打倒迟群和小谢,而且矛头是对着我的。”毛指责邓偏袒刘冰,并将刘信上纲为”当前两条路线斗争的反映”。迟群、谢静宜成了文革的象征。由此引发了所谓大辩论。随后,毛远新奉旨召开了邓小平陈锡联汪东兴参加的四人会议。小毛对全面整顿加以全面指控。邓力辩九号文件以后的形势应由实践证明好坏。并称”昨天晚上我问了主席,这一段工作的方针政策是怎样,主席说对。”老毛听小毛汇报后讲,对文化大革命,总的看法:基本正确,有所不足。授令小毛开八人会议讨论。11月,小毛召开邓陈锡联汪东兴李先念纪登奎华国锋张春桥八人会议,讨论文革认识问题。张指责邓与刘冰立场一致。毛听汇报后讲:阶级斗争是纲,其余都是目。批评三项指示为纲。指令小毛开再扩充人数的小会帮邓。11月20月,毛通过政治局会议要邓主持作一个关于文革基本正确有所不足的决议,邓婉拒并称:由我主持写这个决议不适宜,我是桃花源中人,”不知有汉,无论魏晋”。毛邓关于文革评价的分歧迅猛演变为批邓反击右倾翻案风的政治风暴。

文化大革命沉思之八十

毛的批邓是一步步推进的,从质问到帮助到批评,有几个月从小到大的扩展,毛远新扮演了毛的代表,对邓施压。由于邓的不认错不服输以至拒作文革决议,毛从怀疑到确信:永不翻案,靠不住啊!邓在毛活着的时候,就已表露了对文革的不满,而且要算帐。这是毛绝对不能容忍的。批邓急速升级,11月24日,毛决定在邓主持的政治局打招呼会上宣布他审定的《打招呼的讲话要点》:清华问题是一股右倾翻案风,有些人总是对这次文化大革命不满意,总是要算文化大革命的帐,总是要翻案。两天以后,中央将《要点》传达高层乃至全国,正确对待文革的大辩论由清华扩散到全国。12月20日,邓主持政治局会议并做了检讨发言。邓在说明了整治派性对经济恢复的必要性后,说:检查原因,最主要最根本的,是对文化大革命的态度问题。……主要原因是思想认识问题。会后,邓将检讨发言呈毛审阅。1976年1月1日,权威的两报一刊社论公布了毛批评”以三项指示为纲”的最新指示:安定团结不是不要阶级斗争,阶级斗争是纲,其余都是目。 大悲大喜的文革尾声伴着不断的哀乐奏响,是文革的丧钟。

文化大革命沉思之八十一

1976初邓的二次检讨坦承,以”三项指示为纲”未请示毛也未经政治局和国务院讨论。1月8月,周恩来病逝。邓在周追悼会上致悼词,为他这位五十多年前的留法兄长而于垂暮之年结为政治死盟的战友哽咽挥泪而永別。随后,毛决定华国锋取代邓小平主持中央工作。2月2日毛又决定华任代总理,陈锡联主持军委,叶靠边站。稍后,批邓在党内公开。并公布了小毛整理的毛批邓讲话,择要如下:邓”这个人是不抓阶级斗争的,历来不提这个纲。还是白猫、黑猫啊,不管是帝国主义还是马克思主义。”邓”不懂马列,代表资产阶级”。比较毛对刘、林、邓、周与对江张王姚的批评,轻重立见,对前者,不是一般的批评,而是立场、原则与敌对的指控,是宣布罪状,其罪名是叛徒、内奸、工贼、卖国贼、投降派、死不改悔的走资派,是扣帽子、打棍子,小题大作,而对后者,是善意的提醒,同志式的告诫,恨铁不成钢,小骂大帮忙,大题小作。毛把王明批他的政治帽子全部且添油加醋扣在了刘林周邓头上。而且方法也是如法泡制王明的”残酷斗争、无情打击”。4月4日,迟群等列席政治局会议,批邓”要抢班夺权,另立中央”。为了在文革派与整顿派中平衡,毛决定”政治水平不高”却谨慎忠厚的华接替邓,同时托小毛安抚张,自己曾任十年副手。毛没有忘记庐山会议的震荡。华总理上场了。

文化大革命沉思之八十二

就在批邓从清华园扩散为全国性的批判运动时,地下的异议汇成群众性抗议,从对当局限制周恩来悼念活动及官媒《文汇报》含沙射影批周的蛮行中触发,高高在上的肉食者无视民众的意愿而独断独行,人民则不再愚不可及,沉寂突然被打破,”扬眉剑出销”,这是中共建政以来首次面对自发的、天然的、无计划无操纵的反抗运动,从3月初南京大学生与市民首义雨花台追悼周声讨江张开始,终于天安门抗议群众被镇压,持续了一个月左右,周恩来变成反抗秦皇暴政的旗帜,矛头明白无误指向江青、张春桥,支持邓小平,压抑九年的怒火如火山爆发,突然席卷了从南京到北京的中心地带,十里长街伫立着近百万哭送总理的各界民众,以感天动地的哀泣表达对文革的愤怒,愤怒出诗人,诗歌如雪片纷飞,志士奔走相告,天安门上的花圈与火焰是人心与时代的象征,73年与75年的党内抗争获得了数百万南北民众的响应。深居宫中的病夫感觉无限的沉郁与失落,寻寻觅觅,冷冷清清,凄凄惨惨戚戚,首都,天安门,这是算我二十七年的帐。胡乔木说,毛闭目塞听,没有几个人同他来往。 运动群众的祖师被群众运动了,这位奋斗一生的红太阳终于品尝到了日落时分被全民批斗的凄楚滋味。无以计数的死魂与冤魄齐集中南海,向苍天厚土呼唤正义的报应。

文化大革命沉思之八十三

文化大革命的土地,沉积着一层又一层的冤气、怨气与怒气,不仅仅是贫困,不仅仅是命运的无常或个人的无奈,而是別无选择,绝望,从被压在最底层的贱民一一地富反坏右,二元体制下被剥夺了一切福利保障和权利的农民,被知青困扰的千万城市家庭,历次政治运动被整肃被下放的党政军干部与被改造被羞辱的知识分子,到领袖核心层一批批从天堂摔落地狱的亲密战友们,文革十年,坏分子知多少?帽子知多少?一轮又一轮的百分之五,累计成庞大的数字,画成一个天大的问号,为什么?为什么伟大领袖永远是正确的?革命究竟为了什么?荒诞的是,要不要生产都成了堂皇庙堂讨论的问题。”卫星上天,红旗落地”?如果卫星上天必然红旗落地,要红旗干嘛?”八亿人口,不斗行吗?”难道无休无止的阶级斗争只因人口太多了?从怀疑一切,到怀疑一个人,一个神,越來越多的人在心底里默诵着”庆父不死,鲁难未已”的春秋故事。无数的疑问,无穷的苦闷,对前途的绝望,忧己忧家忧民忧国,空洞的意识形态已无任何感召力,而清明时分的天安门事件是这种怀疑、怒气与怨气的总爆发。

文化大革命沉思之八十四

周的灵魂萦绕神洲。死者纠缠着垂死者。毛圈阅毛远新关于天安门悼念与抗议活动的情况汇报,其中有天安门抗议者”直接攻击毛主席,是建国以来没有的。”政治局会议决定清场。4月7日,毛听取毛远新天安门镇压的情况汇报,颤抖地写下”一首都,二天安门,三烧、打,性质变了”的歪歪斜斜的纸条,连喊”士气大振,好,好,好”。决定向全国公布天安门事件的所谓真相。并决定撤销邓小平党内外一切职务,保留党籍以观后效,决定华国锋任中央第一副主席、国务院总理。接着,是各地党政军首脑表态,游行,庆祝。纵观舆情,轰轰烈烈的表面是强颜欢笑与惨淡的心情,再也没有文革初期造反有理的狂热兴奋,生活的磨难与希望的幻灭早使人们沉入一个个迷茫的岁月。度日如年。4月30日,毛见新西兰总理马尔登时,无奈地叹息”天下大乱”。再后,是追查谣言,特别是一本流传甚广的《红都女皇》的小册子……7月28日,一场唐山大地震摇憾了中国,30万生灵归还地府。年初(4月)的陨石雨与此前毛生日长寿面的断碎,预示着更大的变局。中国人真的酷似《共产主义宣言》的无产者,再也没有什么可失去的了。

文化大革命沉思之八十五

毛对邓”猫论”的令人印象深刻的批判,又一次把论争引到大饥荒时代的62年,或许这一年是毛邓政策裂痕的关键年份,56年以后的反右、反军队教条主义与反修,邓都是毛的秘书长,是副帅,是几个组的组长,是毛的心腹股肱,为毛立下汗马功绩,而面对千万人啼饥哀号的大饥荒,从四川大量调粮而致川民辗转沟洫尸填山野的惨象,邓被震动了,意识形态的僵化教条动摇了。邓、陈未参加59年的庐山会议。对于因批评大跃进而被打成的成千上万右倾分子,邓主持的平反一风吹了,被毛后来批评为”翻案风”。邓毛的隔膜再难愈合。当然,彭德怀骂皇帝的冤案谁也不敢翻。62年7月,邓在中央书记处讨论如何恢复农村经济时说,不管黄猫、黑猫,哪一种方法有利于恢复生产,就用哪一种方法。不久又在见共青团全会的委员时讲,刘伯承同志经常讲一句四川话:”黄猫,黑猫,只要抓住老鼠就是好猫”。邓的猫论传播甚广,形同现代俗谚,只是在流传中”黄猫”传成”白猫”,而毛,死死记住了邓的不改的”黑猫”。

文化大革命沉思之八十六

批邓的纲领,是毛远新整理的1975年10月至1976年1月毛的多次讲话,1976年3月作为中央4号文件发布,题为《毛主席重要指示》。准确地说,这是毛的最后指示,应看作毛的政治遗嘱。毛的这些讲话的全部要旨是对文革的理论做总结,为文革的正当性盖棺论定。毛说:阶级斗争是干什么的?是阶级斗争嘛。刘少奇说阶级斗争熄灭论,他自己就不是熄灭,他要保护他那一堆叛徒、死党。林彪要打倒无产阶级,搞政变。熄灭了吗?……刘、林等反党集团不是令人惊心动魄吗?问题是自己是属于小资产阶级,思想容易右。自己代表资产阶级,却说阶级矛盾看不清楚了。一些同志,主要是老同志思想还停止在资产阶级民主革命阶段,对社会主义革命不理解、有抵触,甚至反对……民主革命后,工人、贫下中农没有停止,他们要革命。而一部分党员却不想前进了,有些人后退了,反对革命了。为什么呢?做了大官了,要保护大官们的利益。他们有了好房子,有汽车,薪水高,还有服务员,比资本家还厉害。……搞社会主义革命,不知道资产阶级在哪里,就在共产党内,党内走资本主义道路的当权派。走资派还在走。

文化大革命沉思之八十七

毛最后一次挂帅出征的批邓讲话,是以阶级斗争为纲的讲道,更似与被禁闭的老战友们争辩,与副帅邓小平争辩,也未忘以哲学家的气势为其操纵的文革理论提供”辩证根据”:一百年后还要不要革命?一千年后要不要革命?总还是要革命的。总是一部分人觉得受压,小官、学生、工、农、兵,不喜欢大人物压他们,所以他们要革命呢。一万年以后矛盾就看不见了?怎么看不见呢,是看得见的。毛信口开河的百千万年革命论与经典马克思主义是风马牛不相干了。毛已无九大对文革的咄咄宏论,而是放下了身段调低了嗓门:对文化大革命,总的看法:基本正确,有所不足。现在要研究的是在有所不足方面。三七开,七分成绩,三分错误……毛承认文革犯了两个错误,打倒一切和全面内战。毛对老同志与造反派各有告戒,不要轻视老同志,我是最老的,老同志还有点用处。对造反派要高抬贵手,不要动不动就”滚”。毛讲批邓运动在党委领导下开展,”不要蒯大富、聂元梓那样的”。最后,毛以导师的身份劝其臣属读点哲学,读点鲁迅……”还可以看郭老的《十批判书》中的崇儒反法部分”。

文化大革命沉思之八十八

对比毛的最后指示与邓的南巡谈话,毛远新讲毛邓治国理念之不同是确实的。但毛邓在党专政方面是高度一致的,毛誓死捍卫文革,邓临终坚守四个坚持,差别在毛是以阶级斗争为纲,邓是唯生产力论,邓有现代化目标,毛没有,毛的革命是无穷无尽的。毛邓的分歧是党治下的纲目之別。76年批邓时,尼克松拜会了毛,后来回忆说:无论别人怎样看待他,谁也不能否认他已经战斗到最后一息了。最后的几个月,6月25日,毛同华谈话时写了”国内问题要注意”最后七个字。差不多同时,毛对华王张汪说:我一生做了两件事情。一件是打倒了蒋介石,把蒋介石赶到台湾,……一件是胜利地进行了无产阶级文化大革命。叶剑英讲话中还有毛这样的话,文化大革命”这笔遗产得下一代,怎么交?和平交不成就动荡中交,搞得不好,后代怎么办,就得血雨腥风了。你们怎么办,只有天知道”。垂死之年,毛似乎预感了什么,他又调出并重温延安时期批王周的”九篇文章”。他梦归故土,思归故土,却不可能。他常常同张玉凤孟锦云看港台电影,讨论《红与黑》。7月,毛虚弱地吟诵了瘐信的《枯树赋》:昔日种柳,依依汉南。今看摇落,凄怆江潭。树犹如此,人何以堪。8月,江青悲叹:主席不在了,我就成了寡人了。 9月9日,弥留之际,毛自语,我不行了,快完了。韶山的太阳终于下山了。江青”悲痛之状,催人泪下”。江才是毛的亲密战友而非亲密伴侣。青年时代的毛写道:我即宇宙,生即死,死即生……人没有万寿无疆1

文化大革命沉思之八十九

历史无法预测。毛死后不到一个月,10月6日,华叶汪调动8341部队逮捕了江张王姚与毛远新。据韩钢的考证,这个行动事先实际上征得了多数政治局委员的同意。又如中央对华悼词所言,华在逮捕行动中起了关键性作用。这应该是实事求是的”还原华国锋”。华汪无法与江青共事,叶更难容忍,在毛造成的你死我活的无法无天政治氛围下,江张王姚与小毛沦为政治斗争的阶下囚,也是罪有应得。据说事变前陈云计算过十大中委的立场,以为通过全会无法解决四人帮问题。非毛化是从华叶汪启始的。77年7月,邓恢复职务。78年12月,陈云扮演了特殊角色的三中全会又一次改变了政局,邓陈胡取代了华叶汪,叶的地位虽未变,但逐步隐为幕后的国老。海内外津津乐道的三中全会的历史性贡献是彻底终结了毛时代的阶级斗争政治,转向周恩来梦想的现代化建设。于平反冤假错案中脱颖而出的正直的胡耀邦注定要在”改革开放”的新时期以”实践标准”独领风骚。文革,终于结束了。曾几何时,中共把文革的一切罪恶归于四人帮,外国人总是举起五个手指。谁会忘记始作俑者呢?

文化大革命沉思之九十

文革对中共高层的震动太大了,教训太深了,天翻地覆。经济重心的转移引起了拨乱反正的平反浪潮。从元勋国老到地富反坏右,所有受到政治迫害的阶层与个人都要恢复公民的平等权利,都要洗刷几十年政治批判的污泥浊水。否则,人心不平,民心难顺。文革后的执政集团,从华叶汪到邓陈胡,都难以迴避国内外与党内外对文革的质疑。从62年七千人大会检讨大跃进到80年四千高级干部讨论历史决议一一实际是检讨文革反省文革一一是共产党内健康力量良知未泯的不懈努力。崔武年讲历史决议是八十年代邓陈老一代政治领导层对文革的反思与论定,是有见识的。也就是说,文革反思有局限,局限于党国元老。文革是亿万群众参与并受难的政治运动,反思必须是全民的反思。反思尚未成功,同志仍须努力。马晓力蔡霞两位女士于文革五十周年之际发动的文革反思就是全民反思的一部分,是接着八十年代的老一辈政治家的反思的,那一次的反思开启了经济改革的现代化进程,这一次的反思能否开创政治改革的宪政议程呢?


Top 10 ReactJS Articles for the Past Month. (v.June)

$
0
0

Top 10 ReactJS Articles for the Past Month. (v.June)

We’ve observed nearly 1,700 articles related to React.JS posted and updated in May-June 2016.

React.JS is a JavaScript library created by Facebook. It is most commonly used in web and native mobile app development.

Mybridge A.I. evaluates the quality of content across the internet and sizes down thousands of articles to Top 10, considering a variety of factors that determine how useful the content are for professionals.

Hopefully, this condensed list will save your time from reading poor quality content and help you learn and code more productively.

Note that Top 10 list for JavaScript, AngularJS and NodeJS, etc. are separated out in order to make this curation more specific to learning pure JavaScript. (See other Top 10).


Rank 1

The Redux Journey by the Creator. Courtesy of Dan Abramov (at React-Europe 2016).


Rank2

22 Amazing Open Source Projects Built with React & React Native.


Rank3

Building F8 Schedule App with React Native [Tutorial Part 1–4] — Trending again in June.


Rank4

On the Spectrum of Abstraction: How JavaScript and React have evolved over the years — Courtesy of Cheng Lou (at React-Europe 2016)


Rank5

Building React Applications with Idiomatic Redux [Free course: 27 episodes]. Courtesy of Dan Abramov


Rank6

Comprehensive guide to building a SoundCloud App with React + Redux.Robin Wieruch


Rank7

React Tutorial: Cloning Yelp


Rank8

Building a React & Flux App with User Authentication. Courtesy of Ryan Chenkie and Scotch Development


Rank9

How to write your own virtual DOM. Courtesy of deathmood


Rank10

Deco IDE: Great tool for building React Native apps is now free and open source.


<Bonus>

No.1) Testing

Enzyme: JavaScript Testing utilities for React — New tool from AirbnbEng

[5,397 stars on Github]

.

.

No.2) Course

Practical guide to building realtime Apps with React Js, Golang & RethinkDB.

[1,921 recommends /4.5 rating on Udemy]

.

No.3) Book

React Native Book for Beginners

Courtesy of Bonnie Eisenman

[4.6 rating on Amazon]

.

.


That’s it for React.JS monthly Top 10. If you like our curation, you can read Top 10 daily articles personalized based on your skills on our iPhone app. It’s free for anyone who wants to read great content.

Read more and achieve more at work.


Review of PocketCHIP Hackable Handheld Linux Computer

$
0
0

Review of PocketCHIP Hackable Handheld Linux Computer

It’s not that easy to describe PocketC.H.I.P in a couple of words, as it’s so versatile. It’s a Debian based portable Linux computer with a resistive touchscreen and battery, but also a retro gaming console thanks to PICO-8, as well as a hardware development platform for IoT application with expansion header providing access to I/Os including GPIOs, I2C, SPI, UART…, and WiFi and Bluetooth connectivity. Furthermore you can easily dismantle the device, in order to use the CHIP board, based on Allwinner R8 Cortex A8 processor, for a different project.

So when Next Thing asked me if I was interested in reviewing Pocket CHIP, I was pretty excited, but when I received it, I scratched my head as there are so many ways to review the item, and it works out of the box with the firmware pre-loaded inside the internal flash, so a getting starting guide would have been too short: “press the power button, and have fun”. So finally, I decided to take a few pictures of hardware, show most of the features, and then go through the different options in the user’s interface.

PocketC.H.I.P Unboxing

I’ve received the device in a black retail package plus a micro USB to USB cable for charging.

PocketCHIP_PackageThe other side of the package has a quick start guide, including a link to PocketCHIP documentation.

PocketCHIP_Quick_Start_GuideBut if you can’t wait, you can most likely jump to step 2, as the device’s battery already has some charge, at least it was the case for me.

Click to Enlarge

The QWERTY keyboard is quite standard, except the number keys are on two rows, and the arrow keys are located on the top left corner.  The display is using resistive touch, so can use both your finger or a stylus for better accurate. You’ll go through a short tutorial during the first boot. The top has through holes for the I/Os, and at first, they look to be arranged in an undulated way, but I had no problem inserting headers, so that’s just a visual effect. The hole on the top right is likely use to add a necklace, although you could use it as a huge keyring too 🙂

PocketCHIP_PencilThe two holes on each side on the bottom can be used to keep the display straight with the left hole for pens (I also use an old USB WiFi dongle with antenna), and the right hole for pencils. I also ended up using mine as the stylus for the screen.

Click to Enlarge

The back of the device has a clear cover revealing CHIP board and the battery (11.1Wh @ 3.7V). You can completely disassemble the unit if you want, but I only pulled out the board with my little green tool. You can watch the video review at the end of this review in case you are unsure how to do.

Click to Enlarge

The top of the board has the USB port, a 3.5mm audio jack, a micro USB port, a battery connector, a 4GB NAND flash, Realtek RTL8723BS WiFi and Bluetooth 4.0 LE module, AXP209 PMIC, and the expansion headers. The power button is located on the top left. Note that if you want to output to HDMI you’ll need to purchase an extra HDMI adapter. You may also have to reflash the board with a different firmware (TBC).

Click to Enlarge

The back of the board is protected with a plastic cover tightened with a single screw, and features Allwinner R8 Cortex A8 processor @ 1 GHz, as well as 512MB Samsung DDR3 memory.

Click to Enlarge

The CHIP board is sold for $9 + reasonable shipping, and should be about twice as fast as the original Raspberry Pi Model B board CPU wise. I wrote a comparison of ultra cheap boards’ features pitting CHIP with Raspberry Pi Zero and Orange Pi One if you want to find more details.

CHIP_Pin_MarkingsI also appreciate the markings written on the side of the headers, which makes life a little easier when wiring, as you don’t need to consult the pinout diagram.

What can you do with PocketC.H.I.P?

So after going through the hardware, I’ll show some of the things you do with the pre-installed firmware. Let’s get started by pressing the power button for one or two seconds. The boot will take a little less than one minute during which you’ll be shown several boot logos, and eventually you’ll be greeted by a short tutorial.

PocketCHIP_Tour

SunVox_Music_PocketCHIP_Tour

You can browse the tour with the left and right arrow key, it’s simply explains you can use the touchscheen with your fingers or a stylus, and the various tings you can do such as playing games, making music. Once we are done with the tour, we get into the main menu with four icons: Terminal, PICO-8 games, Make Music (SunVox), Get Help, Write, and Browse Files.

PocketCHIP_Main_Menu

There are also four icons on the edges of the screen showing battery life and WiFi connectivity, setup and power options.PocketCHIP_Settings

Let’s go inside the setup options since it’s one of the first things you’ll want to do if you plan to access the Internet, as this is where you can connect to your WiFi router, and I had no problem doing so, but note that only 2.4 GHz WiFi is supported, and 5GHz access points won’t be shown. You can also adjust brightness and volume for the audio jack, since there aren’t any speakers.

If you wonder how I took the screenshot for this review, I ran the following command in the terminal which gives me five second to go to what ever menu:

but eventually I did so in an SSH sessions with:

…and found the pictures inside ~/Pictures directory despite the following error showing each time as gnome is not install:

The company latter told me they used “xfce4-screenshooter” for their screenshots, so it should be a better option.

Anyway, time to play with the command line:

PocketCHIP_Terminal

Some command to see system info first:

So the device runs Debian 8 with recent Linux kernel (4.3), the rootfs partition is 3.6GB with 3.0GB free (after installing a few apps), there’s 496MB RAM available to Linux, and the processor is indeed a single core Cortex A8 processor made by Allwinner.

Linux 4.6 will start to support lsgpio to list all GPIOs, but in the meantime, we can still check this with sysfs:

With Linux 3.4 legacy kernel, all the GPIOs would show after loading gpio-sunxi module, but since we are using a more recent kernel, the instructions have changed, and you need to export the GPIOs you want to use as explained on linux-sunxi wiki.

The other good news is that apt is working fine, so you install most of the program that work on Debian. One of the first thing I did was to install openssh-server, because while typing on the device might be fun, it’s also slow, so I found it more convenient to access it via an SSH session from my main computer with the username / password combination being both “chip” (without quotes). I also found instructions to install doom on Adafruit, so I tried it:

It worked flawlessly, and I tried the game by simply typing doom,… and success!

PocketCHIP_doomYou’ll need to connect headphone or speaker to get audio, and playing the game with the keyboard is not that easy as beside the WASD keys, you also need to the left and right keys placed just above. So it might be better to connect a USB keyboard to the USB port of CHIP board, or re-assign the keys if possible. Apart from that, the games runs perfectly smoothly.

Let’s go back to the main menu to try PICO-8 retro games, and again you’ll go through a short tour explaining how to use the app to play or edit games with your own sprites.

PICO-8_Tour

PICO-8_Tour_CelesteAfter the tour, you’ll be presented by a selection of 4 “favorites” games: Celeste, Frog Home, Hug Arena, and Tower of Archeos, but you have access to many others games too. I tried Celeste, and no problem, except I need to practice more 🙂PICO-8_CelesteThe option to “edit this cart” will bring you to the games code, which you can edit as your wish.

PICO-8_Game_CodeThere’s also PICO-8 terminal to perform various actions such as loading files,  creating directories, and so on.

Next up the Make Music app (SunVox) will also take you through a tour first.

SunVox_Tour

After connecting headphone or speaker, you’ll be able to compose and play music on a MIDI keyboard.PocketCHIP_Sunvox

The application definitely requires a stylus – a pencil will do – especially the top menu options, and even kids’ fingers will be too big.Sunvox_Menu

The four icon in the main menu starts an help section with a scrolling bar. So much to say about this one.PocketCHIP_Help

The “Write” icon is a text edit, which turns out to be Leafpad 0.8.0.1. It could be your text editor to write Python or other languages programs, before running them in the command line.PocketCHIP_Leafpad

Finally the File Browser is the commonly used PCManFM 1.2.3, and allows to copy, delete, move, or create files or directories.

PocketCHIP_File_Manager

So I’ve gone through all options provided on the pre-loaded firmware, so it’s time to turn it off. You can click on the bottom right corner to select Shutdown, Sleep, or Reboot options, as well as “Flash firmware” to reboot into software flashing mode. You can then follow the firmware flashing instructions @ http://pcflash.getchip.com (Chrome browser required).PocketCHIP_Shutdown_OptionsIf you prefer a video review, and I’ve embedded mine below. I checkout the hardware until 3:05, before starting the device, and showing it action.

So overall, PocketC.H.I.P is a fun device to use, and should be particularly interesting for kids, as they can play games, compose music, and learn about Linux, programming and/or hardware hacking with this inexpensive all-in-one device. PocketC.H.I.P is currently available for pre-order for $49 + shipping for a limited time, after which it will sell for $69.

Read more: http://www.cnx-software.com/2016/06/25/review-of-pocketchip-hackable-portable-linux-computer/#ixzz4Cne7rgb5


Awesome React Boilerplates

$
0
0

Not interested in reinventing the wheel? Neither am I. Here’s a short list of awesome React boilerplates – sometimes knows as starter kits, seeds or skeletons – for getting React-based applications off the ground in a hurry. These application templates were not taken from any list, however awesomethat list might be. Rather, they’ve gained enough mindshare to find me outside The Stream1. They’re open source and waiting for you to clone, fork and build upon for your next React project.

React

Application boilerplates for creating React apps.

react-redux-universal-hot-example
A starter boilerplate for a universal webapp using express, react, redux, webpack, and react-transform

react-starter-kit
Everything you need to build a front-end for a SEO-friendly React website. Supports text-only browsing and focuses heavily on Node.js and the surrounding ecosystem of NPM libraries. For an example isomporhpic application I’ve built using this kit check out lumpenradio-com or myIsomporhpic Rendering with React talk.

react-redux-starter-kit
By former colleague (and one hell of a coder) this kit is designed to get you up and running with a bunch of awesome new front-end technologies, all on top of a configurable, feature-rich webpack build system that’s already setup to provide hot reloading, CSS modules with Sass support, unit testing, code coverage reports, bundle splitting, and a whole lot more.

react-slingshot
React Slingshot is a comprehensive starter kit for rapid application development using React. Includes React + Redux starter kit with Babel, hot reloading, testing, linting and a working example app, all built in.

hapi-universal-redux
Isomorphic starter kit with server-side React rendering using npm, piping, webpack, webpack-dev-server, react-transform, hapi.js, babel.js, react.js, redux, redux-devtools, simple-redux-router, react-router, radium.

hapi-react-starter-kit
Another isomorphic boilerplate chalk full of features for the taking.

Este
A React/Flux dev stack and starter kit for Universal JavaScript apps. Renders pages SPA style (using script tags) and, therefore, is not as SEO friendly as React Starter Kit.

re-base
Inspired by Relay, combines the benefits of React and Firebase by allowing each component to specify its own data dependency. Forget about your data persistence and focus on what really matters, your application’s state.

electron-react-boilerplate
Electron application boilerplate based on react, react-router, webpack, react-hot-loader for rapid application development

relay-starter-kit
Barebones starting point for a Relay application. Uses the Babel Relay Plug-in and linked to from the official Relay documentation so it’s likely to gain traction as a starting point for new apps.

jspm-react
Configured starter repo to build web apps with React and ES6 modules using JSPM. Not actively maintained, though the author is still accepting pull requests.

React Native

Application boilerplates for creating React Native applications.

pepperoni
An aspirational open source starter for React Native and jam packed with lots of tasty ingredients.

react-native-webpack-starter-kit
Build your React Native app with Webpack and Babel.

snowflake
A React-Native starter kit using Redux, Parse.com, Jest

react-native-es6-babel
Configuration to build React Native apps with ES6 using webpack and Babel

react-native-es6-reflux
Boilerplate for iOS app development with React Native, ES6 and Reflux

react-native-tabbed
An unassumingly but sweet base for a native app with tabbed navigation and modal window support. Builds on the work of react-native-navbar. See it in use with React Native Icons in mySmartphone Symphony app.


React Native开发技术周报Issue#15

$
0
0

React Native开发技术周报Issue#15

尊重版权,未经授权不得转载出处:http://www.lcode.org

本周报来自江清清的技术专栏,欢迎微信关注公共号:codedev123.精彩技术文章第一时间推送!

说在前面的话:React Native开发技术周报,主要会涉及React Native最新资讯,React Native教程,技术开发文章,开源项目,工具,视频等等。今天是我们的第十五期,同时各位朋友有优秀的有关React Native技术开发文章可以发给我。

React Native交流7群:131537844

(一).资讯

1.React Native 0.29-rc版本发布

2.React Native培训免费电子书

该电子书不错,虽然是英文的,整理来讲简明意赅的感觉。

3.腾讯新闻React同构直出优化实践

性能优化,干货推荐。

(二).技术文章

1.React Native进阶之Animated动画库详解-实例篇

Animated动画在用户体验中是非常重要的一部分,Animated库可以用来构建流畅,强大,并且容易构建以及可维护的动画。本篇主要讲解Animated动画库的基本使用。

2.React Native模块之InteractionManager(交互管理器)详解

使用InteractionManager可以让一些耗时的任务在交互操作或者动画完成之后进行执行,这样使用可以保证我们的JavaScript的动画效果可以平滑流畅的执行。可以大大提升用户体验。

3.React Native模块之Timers(定时器)详解

Timers(定时器)是应用中非常重要的部分,在React Native中实现和浏览器一致的Timers。

4.使用 ES6 来为异步函数记录执行时间

在这篇文章里,我会实现一个可重用的函数来处理 JavaScript 延时异步操作。

5.React-Native For Android 环境搭建及踩坑

6.ReactNative iOS源码解析(一)
绝对干货,分析了React Native iOS部分框架的初始化流程以及OC和JS的相互调用原理分析
7.你想知道的关于JavaScript作用域的一切(译)

JavaScript中有许多章节是关于scope的,但是对于初学者来说(甚至是一些有经验的JavaScript开发者),这些有关作用域的章节既不直接也不容易理解. 这篇文章的目的就是为了帮助那些想更深一步学习了解JavaScript作用域的开发者,尤其是当他们听到一些关于作用域的单词的时候, 好比:作用域(scope),闭包(closure),this,命名空间(namespace),函数作用域(function scope),全局作用域(global scope),词法作用域(lexical),公有变量(public scope),私有变量(private scope). 希望通过这篇文章你能够理解。

8.React Native中 Back 键的攻坚实战

9. ES2015实战——面向未来编程

 针对ES2015的知识体系做了集中整理分享,非常不错,超级赞。

10.在React Native中优雅的使用iconfont

关于在React Native中使用iconfont,网上已有很多非常好的解决方案,用的最多的就是react-native-vector-icons , 这个库支持很多常用的iconfont,比如FontAwesome, Ionicons, MaterialIcons等等。但是这个库依赖了不少iOS和Android的原生代码,这让一个前端开发脸上浮现了一个大大的懵逼。 而且自带的字体文件都偏大,做起精简来简直想哭,更别说加入自定义的iconfont了。所以本文给大家介绍如何以非常优雅的姿势进行使用iconfont库。

11给React Native开发的应用添加widgets

widgets应该是android平台上最有用的特性之一了吧,将应用的数据利用一个小视图嵌入其他应用(如桌面),可以快速地获得app的状态而不用启动app。本问主要讲解这个知识点。

12.精益React学习指南

这本书我会由简单到复杂的带领大家进入 React 的世界, 其中 1 – 3 章节都是 React 的基础知识,需要提醒读者的是大多数的基础知识都可以通过 React 的官方文档学习,如果对英语敏感的读者也可以看翻译。 对比官方文档本书 1 – 3 章会循序渐进的带领大家学习 React 基础知识,其中会有些自己的见解和领悟希望能让读者更容易理解学习,每个章节都会有一个实例作业。

13.【React Native for Android】jsBridge实现原理

本文虽然讲的内容不多,但是精益求精了,图文并茂。

14.React Native系列文章(十)react-native-scrollable-tab-view(入门篇)

15.React Native系列文章(十一)react-native-scrollable-tab-view(进阶篇)

通用的Tab标签器,非常不错哦~非常赞。

16.React Native 封装Android 原生View实例

实例讲解封装原生View控件。

17.React Native开发之动画(Animations)

本文主要讲解动画的基本使用。

18.react-native动态修改server host

大家都知道android端的react native可以运行时修改server host,开发模式下摇一摇设备,呼出调试菜单,就可以修改server host,不需要重新打包很方便。不知道为什么,iOS环境却没有提供相关功能。于是这个工具就出来了:react-native-debug-server-host。我们知道直接修改源码很容易实现需求,但不侵入原有代码才是上策,后面部分有实现原理的简单介绍。

19.React-Native 之控件布局

20.React组件性能优化探索实践

React本身就非常关注性能,其提供的虚拟DOM搭配上Diff算法,实现对DOM操作最小粒度的改变也是非常的高效。然而其组件渲染机制,也决定了在对组件进行更新时还可以进行更细致的优化。

(三).开源项目

1.React Native开源项目-漫威电影客户端

一个在F8基础上照猫画虎的漫威React Native App. 支持Android和IOS。 想要自己运行app的话,到http://developer.marvel.com/ 上申请API key,添加到env.js中。主要功能点:显示流行的漫威角色,搜索漫威character, event, story, series,Android,iOS双平台支持

2.React Naitve开发的Cool zjapp客户端

这一个RN的练习项目,包含了许多功能点以及第三方库的使用,在开发中或多或少会用到,与君共勉。功能:1 自定义封装了类知乎客户端的tabbar,并且伴随滚动逐渐隐藏和显示头部底部功能。2 实现本地通讯录的交互(用的是ScrollView数据多可能会卡顿)3 拍摄或者选择图片剪切头像(react-native-image-picker 有些bug)4 获取本地图片 实现自定义相册功能(全部获取所有图片,对数其进行分类可以实现分类相册功能)5 MD设计风格的第三方库(react-native-material-kit)

3.React Native一些实例Demo整理-有一些非常有特点的库使用

4.React Native的图片画廊效果开源库

(四).工具

1.babel到底将代码转换成什么鸟样?

将babel捧作前端一个划时代的工具一定也不为过,它的出现让许多程序员幸福地用上了es6新语法。但你就这么放心地让babel跑在外网?反正我是不放心,我就曾经过被坑过,于是萌生了研究babel代码转换的想法。本文不是分析babel源码,仅仅是看看babel转换的最终产物。

es6在babel中又称为es2015。由于es2015语法众多,本文仅挑选了较为常用的一些语法点,而且主要是分析babel-preset-2015这个插件(react开发的时候,常在webpack中用到这个preset)。

2.我的 React Native 技能树点亮计划 の 代码风格统一工具 EditorConfig

EditorConfig 通过在工程中增加一个配置文件以及安装对应的插件,实现在不同编辑器和 IDE 保持工程中代码文件编码格式的一致性,EditorConfig 的配置文件具有良好的可读性,并能很好的和版本控制系统一起协作。

(五).视频

1.ReactEurope 大会演讲视频(请注意科学上网)

2.构建React Native Android部分大量数据,高性能的列表视频

3.RN框架工程师介绍React Native架构以及最佳实践(请注意科学上网)


做一个 App 前需要考虑的几件事

$
0
0
做一个 App 前需要考虑的几件事

随着工具链的完善,语言的升级以及各种优质教程的涌现,做一个 App 的成本也越来越低了。尽管如此,有些事情最好前期就做起来,避免当 App 有了一定规模后,再感慨当初为什么没有多留点心。

完善的日志系统

以 iOS 为例,有时图方便,就直接用 NSLog 了,甚至线上都一直开着。一方面会影响性能,尤其是输出比较频繁的时候,另一方面也容易泄露敏感信息,所以一般做法是在 Release 模式下禁用NSLog,比如在 pch 文件中,通过对环境的判断,对 NSLog 做不同的处理。

但这样仍会有问题,比如我们发现线上的 App 在特定场景下会有某种异常的表现,这时就很希望能有日志来提供更多的信息。可以考虑使用像 cocoalumberjack 这样功能更完善的第三方日志工具,在线上仍然开着日志,但不消费,这样就不会泄露敏感信息。当我们需要看日志时,可以通过「调试模式」打开它,然后连上 iOS Console 来看。

因为 Log 是一个很普遍的行为,所以最好前期就规范起来,后期遍地都是 NSLog 时,再要改动会有点麻烦,当然也可以偷懒点,直接把 NSLog 的宏定义改了。

Commit Message 规范

在前期开发的时候,往往为了快速实现功能,而忽略了 Commit Message 的规范,然后就会出现很随意的 Commit 信息。这样别人在 Review 代码时就会很累,写某个版本的 Release Notes 也会变得艰辛,甚至过一段时间自己都不知道这些 Commit 代表的意思。而如果自己也讲不清这次改动究竟该怎么描述时,往往是这次改动混杂了较多的信息。

这篇文章 简洁精确地描述了为什么要写好 Commit Message,以及如何写。遵守这些规范后,就很方便产出这样的 Release Notes 了。

代码规范

这个最好在前期就抓起来,如果前期不做约束,每个人的风格往往会有比较大的差异,导致代码看起来会比较累,甚至有些人是从其他语言转过来的,还会保留之前语言的一些书写习惯,就容易有「出戏」的感觉。一致的代码规范不仅看起来舒服,而且让团队更像一个整体。

这个实施起来会有一定难度,尤其是团队中有一些「老人」的时候,他们往往积累了一套自己的编程习惯,而且不容易被说服。

准备一份编程守则

里面包含了「最佳实践」和「不要踩的坑」,这个可以一定程度上提高开发效率,避免一些低级错误。比如以 iOS 为例,「不要随便使用通知」,因为通知使用起来太方便了,用得多了调试起来就会很累,而且也不好管理;「通知用完之后记得 remove observer」;不要使用containsString(如果还需要支持 iOS 7 的话)。随着时间的累积,这份守则里的内容会越来越多,也是一件挺宝贵的财富。

页面布局规范

这个在 Android 相对还好,基本都是通过 xml 来进行布局。在 iOS 里玩法就多了,有用 storyboard 的,有用 xib 的,有直接计算坐标和大小的,有用原生 autolayout 的,有用第三方布局类的。总之就是各显神通,尽量用同一种布局规范(但不建议直接计算坐标和大小),看起来也会方便些。

统计埋点

这是很重要的一块,客户端所有的数据基本就靠它了,所以尽量选择一个灵活、稳定的数据方案,同时最好在他们提供的 SDK 上再封一层,方便做一些额外的事情(比如想同时接入另一家服务作对比)。

统计埋点还有很重要的一点是「验证」,是否有错打、漏打等现象;iOS / Android 是否有用同一个点;有些点还需要额外的参数,这些参数的格式是否正确等。这些工具往往只能自己来做了,这也是比较花时间的一部分。

App 架构

App 架构会随着业务、人员的增长而演进,所以当发现当前的架构无法满足日常的业务迭代时,就需要考虑对它做调整了。一般来说,大方向上也就是 MVP / MVVM,等人员多起来时,基本就是组件化开发,当然组件化也会有它的问题(比如资源 / 类重用、组件间通信等),这里就不展开了。

在前期选择一个相对轻量级,但比较清晰的架构(尽量不要选择 MVC),大家都遵守这个架构开发,也能一定程度上提高效率。

页面跳转机制

虽然 Android、iOS 都原生支持 open 特定 scheme 的 url,不过可能的话,还是通过 router 统一处理会比较方便,也更灵活。比如可以知道注册了哪些 URL;可以知道页面的跳转成功率;方便处理一些奇奇怪怪的需求等。

在线配置

在线配置可以赋予 App 极大的灵活性,比如运营的一些活动、banner 位调整、首页弹窗等;还可以针对特定机型、系统分发特定的内容,结合规则引擎甚至可以给一部分有相同特征的用户发推送;可以做流量切分等。所以一个强大/稳定的配置中心就显得尤为重要,A/B Test 也可以基于配置中心来做。

这里有些注意事项,因为不少配置的值是运营填的,她们对 value 不那么敏感,所以会出现 value 为空,或者不是想要的类型,或者配了张图片,但是体积超大等,有可能造成客户端 crash / OOM 等异常表现,所以客户端要有足够强大的容错能力。

选择合适的 Crash 平台

Crash 会给用户造成极大的负面体验,所以需要经常关注 Crash 情况,尤其是刚发版的那段时间。这块 fabric 做的比较好,只是由于是国外的服务,会有些许数据上的丢失,不过问题倒也不是很大,也可以考虑国内的一些服务,如 bugly,毕竟腾讯自己也在用。

Code Review

这也是容易忽视的一点,当业务需求压过来时,先把功能实现了再说,而且在初期往往人手也不够,抽不出时间来做 Code Review。如果是这样的话,可以先 Review 一些核心的点,保证重要的代码是经过 Review 的,不太重要的业务代码可以先放放,等人员充足后再覆盖更大的范围。

Code Review 的主要作用是保障代码质量,同时促进双方成长,一个担心点是质量偏低的代码比例如果较大的话,会影响开发者的心情,增加维护成本,日积月累就成了重重的「历史包袱」。

选择合适的开发模式

如果是使用 git 来做源码管理的话,可以采用 flow 模式,基本能满足大部分的需求,而且不少 git 工具也内置了 flow 的支持。这样当需要处理 feature / hotfix / 发版等场景时,就会很方便。

持续集成

持续集成的目的是让产品在快速迭代的过程中还能保证质量,当有错误发生时,可以第一时间被检查出来,方便修复。如果想偷懒的话,可以直接使用成熟的服务,如 travis,也可以自己基于 Jenkins 来搭,iOS 的话,配合 fastlane 效果会更好。自己搭的好处是灵活度更大,可以加入一些个性化需求。

如果有打包平台的话,还可以定时出一个包,这样当发现某个功能使用起来有问题,代码上又没什么头绪时,可以对比以前的包来定位。

Bug 管理系统

这个 Bug 包括测试阶段和线上的 Bug,Bug 管理工具有很多,使用在线服务或自己搭都可以,但要有,不然很有可能忘了还有哪些问题需要修复,哪些已经修复了。

项目管理工具

在 App 开发初期,人员较少,沟通起来比较方便,所以很多需求当面就说了,一些原型/设计图可能也是直接 AirDrop 过来的,这样效率自然高,但不便管理。比如没有 prd,产品、开发的理解可能不一致,到头来发现做的不是产品想要的,或者一些细节不符合要求;设计图有更新,但没有同步到所有的开发;需求有变更,但当时在专心做某个 feature,可能就忘了,或者没有理解全面等。所以最好还是有一个项目管理工具来统一处理,再结合敏捷开发,项目的质量和进度就容易得到保障。

Checklist

一个 App 发布上线之后,要保证不出大的问题,就要在发布之前,先检查一下「一定不能出问题」的点是否正常,就像飞机起飞之前一定会走一遍 checklist 一样。比如推送是否正常、log 是否关闭、组件版本是否正确等,随着 App 功能的增加,这个 list 也会越来越长,虽然过一遍 checklist 会花费些时间,但跟收益相比还是值得的。

以上这些点是在感受不过不同量级的 App 开发后整理的,肯定还会有疏漏,不过如果真能做到这些,就已经很不错了,至少当有新人进来时,不会背上沉重的「历史包袱」。



技术层面并无革新性突破,高通、GE、Intel等巨头为何不惜重金投资无人机企业?

$
0
0

技术层面并无革新性突破,高通、GE、Intel等巨头为何不惜重金投资无人机企业?

技术层面并无革新性突破,高通、GE、Intel等巨头为何不惜重金投资无人机企业?

在2016年CES展上,无人机与VR/AR、电动汽车等一起,成为智能硬件领域吸引大量关注的热点。大疆除了推出“精灵”及“悟”新型号产品外,还同时发布了Mobile SDK 3.0,并启动2016年度DJI开发者大赛,福特汽车也赞助了这项赛事,福特与大疆希望通过这一赛事,开发无人机与汽车联网技术,实现搜救及其它行业应用。

2016年5月,零度智控的DOBBY、小米无人机先后推出,网上风靡一时的Hover安全自拍无人机宣传和众筹活动也哄哄烈烈的展开,几个产品各自从便携、低价、安全自拍等不同的消费热点切入。

实际上,早在2013年甚至更早的时候,国内外在无人机领域的创业和投融资大潮就轰轰烈烈的展开了。2015年4月,随着大疆7500万美元融资计划的披露,该公司估值超过100亿美元;与此同时,极飞、亿航先后获得融资,无人机行业进入蓬勃发展阶段。

几乎可以肯定,未来无人机的天空有巨大的“造梦空间”。根据研究机构EVTank发布的《2015年度民用无人机市场研究报告》数据显示,2014年全球民用无人机销量为37.8万架,占比高达96%,增长势头迅猛,其中专业级无人机销量占33%,消费级无人机销量占67%。预计2015年全球民用无人机将同比保持50%的增长态势。到2020年,全球无人机年销量有望达到433万架,市场规模将达到259亿美元。

下表是对市场上几家著名的无人机厂商的融资情况和技术特点做一个简单的总结。

看到上面的融资及产品发布现状,结合下面2014到2015的Gartner技术成熟度曲线,基本可以认为,无人机技术已经度过了“创新萌芽Innovation Trigger”期和“期望最顶点Peak of Inflated Expectation”的早期,进入稳步发展时期,甚至可以预见,在未来的5到10年里,恐怕将有一批创业企业无以为继,市场开始洗牌重组,而后进入稳步增长期。

Hype Cycle for Emerging Technologies, 2015

Hype Cycle for Emerging Technologies, 2014

从投资角度来看,无人机现阶段渡过了早期技术孵化器,将在几年后进入后期稳定发展期,是一个稳健投资的窗口。

另一方面,面向普通消费者的消费级无人机从功能到主要玩家,格局基本已定,很快进入产品厮杀阶段,虽然不乏有新技术不断涌现,但总体来说已经过了投资窗口;工业级无人机的概念是近一到半年才慢慢成型,与消费级定位于增添乐趣和体验的出发点不同,工业无人机是从直接的行业需求中来的,对于功能的精准定位、高环境适应性和高可靠性有着近乎苛刻的需求,直接关系到用户体验和市场推广,是值得关注的领域。

下面先进行一些无人机技术的基本技术分析,在次基础上,分别针对消费级和工业级无人机进行基本情况介绍。

1、无人机简单技术分析

目前看来,市场上较为流行的消费级多旋翼无人机中,无论是在飞控算法和云台控制上有优势的大疆,还是在自动控制和传感器应用上具有技术领先的3D Robotics和Parrot,其操作系统架构基本由中央处理器(MCU、ARM早期型号、ARM Cortex系列)、外围传感器(GPS、超声、摄像头等)、电机和电机驱动芯片、数传模块和图像传输模块组成。总结如下:

回顾大疆的发展历程,历数近几年来成功融资的各个无人机制造商,可以看出来:

首先,大疆的成功在于实现了从0到1的突破,实现了无人机从完全手动控制到自我稳定姿态+人工控制的良好平衡点,将无人机从专业航模领域拉低到了普通爱好者圈子,玩无人机不再是少数专业爱好者的专利。

在此基础上,大疆瞄准了航拍应用的市场,以航拍特点为需求,不断调整自己的飞控算法,研发了独有的云台系统,逐步占领了航拍市场。

自大疆以后,陆续兴起的各大无人机厂商,在此基础上并无革命性的突破,飞控算法都是基于APM等开源系统调试,主要发展方向包括:

1) 针对消费类市场,添加智能终端APP控制,进一步占领普通消费者;

2) 针对普通玩家,进一步添加无人机自我控制,如无操作悬停、自动返航、主动避障等;

3) 针对航拍市场,添加巡航拍摄,定点绕拍等细化功能;

4) 针对垂直应用领域,如植保、安全巡检、安防等细化功能。

总体来说,上述各个发展方向,在技术层面并无革新性突破,但近几年来无人机行业频频受到风投行业的亲睐,尤其是高通、GE、Intel等行业巨头都不惜重金投资无人机企业;2015年8月26日,Intel以6000万美元投资上海无人机公司Yuneec,Intel股票应声大涨5.5%,此前,Intel还投资了Airware和PrecisionHawk两家无人机公司。

在无人机市场同质化竞争如此激烈的今天,为何各大产业巨头仍未放弃该市场,应该说,其根本原因在于在未来,无人机将不再是一个简单的飞机,而是成为物联网的延伸成为Sensor、AI、CV、AR\VR等各项技术的载体,其可以可以飞行的特质将为上述技术提供一个高机动性的载体。


2、消费级无人机看点

2016年5月,零度智控的DOBBY,小米无人机先后推出,网上风靡一时的Hover安全自拍无人机宣传和众筹活动也哄哄烈烈的展开,几个产品各自从便携、低价、安全自拍等不同的消费热点切入,相信各自的卖点打动了部分消费者的心,这从其众筹的火爆程度可见一斑。但平均2000-3000的售价,并非刚性的需求,究竟多少人愿意为此买单?

零度智控的DOBBY

零度智控市场负责人孔祥玉曾表示,2015年10月份,零度智控就基于高通骁龙801平台推出了整套无人机方案。基于手机芯片的无人机整体解决方案,可以将无人机做得更小,更加智能,更容易扩展。通过丰富的拓展接口和机载运算能力,可以为众多开发者提供更广阔的应用空间。

无独有偶,除了高通,本土做IC芯片设计的公司也开始涉足无人机领域,瑞芯微将昔日用于互联网电视盒子、Android平板及Chrome笔记本的RK3288芯片,引入了无人机领域。瑞芯微相关人士表示,通过这款芯片,瑞芯微在无人机领域目前是以影像处理为首要目标,主打防抖高清航拍功能。

小米无人机

Hover Camera

总体看来,消费级无人机基本集中在软硬件平台的开拓和市场占领,并在此基础上引入各种贴近生活、增加娱乐体验的功能。此外,本体设计也是不容忽视的问题,国外因为旋桨致盲致伤的案例已经不断发生了。

3、工业级无人机看点

所谓工业级无人机,是指服务于具体垂直行业,以集中解决行业问题、提升工作效率为目标的无人机。

典型的工业无人机机领域包括电力线巡检、安检安防、农业植保、森林防火、航空测绘、警用和消防等方面,与消费级无人机最大的不同在于,工业级无人机需求直接来源于具体行业,并且作业环境特殊,环境适应性和可靠性要求高。

与消费级市场不同的是,工业级无人机市场还处在比较原始的阶段,总体技术落后、市场混乱,造成这种局面的主要原因是:

1)  销售渠道匮乏。个别企业虽然技术处在行业前列,产品种类齐全,飞机性价比很高,却缺乏销售渠道和关系网络,不能进入政府或者某些行业大型企业的采购目录,无法进行大规模销售。目前收入主要来自于项目制带来的无人机的销售、服务以及为科研院所、高校等ODM无人机。

2)  产品单一,技术积累薄弱。例如有些企业只有四轴多旋翼一种类型的无人机,由于四轴没有动力冗余,坏掉任何一个桨飞机就会坠落,在工业领域应用存在一定的风险,因此在应用范围上受到一定的限制。

3) 产品定价过高,性价比差。有些企业虽然技术指标处在行业前列,但是产品定价过高,性价比差。虽然依靠一定的企业、政府关系网络有一定的销售,却难以大范围推广。例如同样一款续航30分钟左右的无人机,该企业的售价在60~80万元,而另一家企业同样参数的产品售价只有4.5~6万元。

4) 团队不稳定。例如某工业级无人机企业创始团队多次分裂,虽然有一定的技术,却影响了企业整体的发展。

如上所述,目前国内外工业级无人机市场还处于混乱状态。

在国外,硅谷创业公司Skycath主打工程测绘和数据收集,典型的案例就是和日本小松集团合作,推出智能化工程(Smart Construction)项目。据介绍,小松公司的智能化工程项目可实现由一队无人机测绘三维地图,然后指导机器人控制大型工业车辆作业。

使用Skycatch无人机绘制地图不但节约时间,同时减少了犯错的机会。无人机将配备立体摄像头,系统能够以三维数据的形式,获得施工人员和其他建筑机械的作业结果(地形变化)。然后对当前数据与施工前使用无人机测量的地形数据、三维竣工图的数据进行自动对比,从而提高施工效率并管理施工进度。此前小松测量团队利用传统方法绘制某块区域的地图大约平均需要两周时间,现在使用无人机在一天之内就会完成全部绘制工作。

经过实地走访,我们发现,位于美国旧金山,曾经轰动一时的无人机创业公司3DR也正式退出消费级无人机市场,转而进入工程测绘领域。

国内,从事工业级无人机研制的企业包括已经在新三板上市的易瓦特、臻迪和专注农业的极飞等企业,但是在本体制造和可靠性、以及高效率解决行业问题上还存在一定问题。

另外,近期比较火爆的农业植保领域,无论是市场占有较快的极飞,还是陆续杀入的零度、大疆,在无人机本体制造和应用解决方案上,都还存在不少问题,实际应用效果不尽人意。

至于电力线巡检等特种领域,由于其全天候的要求特性,对于无人机本体抗风能力、抗电磁干扰能力均有较高要求,这是一个系统化的工程问题,目前国内的无人机制造厂商,鲜有能满足要求的。

国内最近崛起的工业级无人机研发制造商博瑞空间,除了有人工智能、机器视觉和三维测绘方面的技术积累,在多旋翼机身动力学、动力冗余设计、抗大风/电磁干扰等恶劣环境方面都有一定的技术积累,适合工业级环境应用。

4、未来无人机投资和发展预测

那么,究竟如何看待未来无人机的发展呢,可以说,无人机前期的概念炒作已经过去了,人工智能、视觉辅助、语音辅助等方方面面的技术已经基本成熟,消费级的应用层面进入常规创新期。

值得关注的是,无人机的本体方面功能有待加强,无论是针对消费级的安全设计,还是针对工业级的本体、控制、电池、可靠性方面,从航模到工业品,还有很长的路要走。毕竟,任何功能和行业应用,都离不开无人机本身这个扎实可靠的载体。

对于投资方面,可以重点关注一下无人机本体做的比较扎实的公司。等到无人机本体制造达到了工业级水平,各个垂直行业才会真正进入规模化实用阶段。

本文内容来自“享投就投”微分享活动,作者王冠,分享投资投资总监,负责集成电路、传感器、新型器件等方面的投资,在电子信息、通信领域拥有十年的工程研发经历,先后任职于航天科技集团九院和英飞朗科技(北京)有限公司。


Setup Swift 3.0 on a Raspberry Pi 2/3 with a headless Raspbian. Step-by-step

$
0
0

Setup your Raspberry Pi 2/3 with Raspbian headless (without cables)

As mentioned in a previous article, I need to control some electronic circuit with the GPIOs pins of the Raspberry Pi. I could easily achieve that with Python or C. But I am a cool kid. I want to use Swift.

Jokes aside, I work full-time with Swift, so I got pretty good at it. And I think it will be a great language for robotics.

The plan is that I am going to install Raspbian (Debian customised for Raspberry Pi), configure it and then install the Swift 3.0 binaries.

Background excursus

The Swift team is supporting Ubuntu as their main Linux distro. Ubuntu is great. But to setup a basic Ubuntu installation, you need a monitor and keyboard. With Raspbian, you just turn the RPi on and after 2 minutes it has configured itself. It will have a default user ready. And it comes with installed WebMD, which exposes the machine to the network. So you can immediately ssh into the it. Pretty handy.

Step 1: Preparation

Get your Raspberry Pi 2 or 3, an SD memory card with 8Gb or more memory (class 10 or more), a micro USB cable and an ethernet cable and the Wifi USB dongle.

Step 2: Flashing Raspbian on the SD card

Start by downloading Raspbian Jessie Light (no GUI. GUIs are for posh folks. or kids. or non-techies. or people who want to actually do some productive work. not for you).

No you have to flash the image you just downloaded to the SD card. On the web you find a lot of multi step command line guides. But that’s nuts, since you have a great apps, called Etcher.io, that make the process incredible simple, faster and safer.

Download Etcher app (for all platform), then select the Raspbian image, the SD card (which you have to insert in your computer) and flash it. Few minutes and it will be done and verified.

Put the SD card into the RPi, you’re ready to rock!

Step 3: Ssh-ing into your RPi

After you’ve inserted the freshly backed SD card into your RPi connect the ethernet cable between the RPi and your router. Turn the RPi on by connecting the micro USB cable to the electricity or to your computer.

Wait 2–3 minutes, then open your terminal and type:

ssh pi@raspberrypi.local
(password raspberry)

You should be in! That’s badass like the Administrator in the movie Hackers.

You are now connected to the RPi via the network. The only problem is that you still need to keep the RPi connected to the network through the ethernet cable. But let’s address that.

Step 4: Going wireless

Attach the USB dongle to your Raspberry Pi. Then, while connected to the RPi with ssh, open the wireless configuration file:

sudo nano /etc/wpa_supplicant/wpa_supplicant.conf

and add at the end of the file the informations about your wifi network:

network={
    ssid=”your-network-ssid-name”
    psk=”your-network-password”
}

Save and exit the editor. Remove the ethernet cable and then reboot with:

sudo reboot

Now in about 30 seconds your RPi should be up an running. If you try again to ssh into the RPi should just be able to connect as before. But on wifi!!

Step 5: Final configurations

I suggest you to secure your login with a rsa key authentication and enabling it only the port 22. Here a guide.

A classic system update is also suggested:

sudo apt-get update
sudo apt-get upgrade

The-wise-guy-last-step: Backup your RPi

It’s very easy to burn an SD card by writing to it too many times. Or irreversibly fuckup your configuration by doing what sudoer should not do. Cloning your SD card, as an image that you can flash on a new card when you need it, is the perfect backup strategy. Here you find how.

You are now ready to install Swift on your hot-n-sexy Raspberry Pi.

To get my latest Swift misadventures subscribe to the publication. Cheers.

Installing Swift 3.0 preview on a Raspberry Pi 2/3 with Raspbian

We’re halfway trough our journey of controlling electric circuits and hardware with Swift and a Raspberry Pi. If you missed anything, here lie the answers to your questions.

Ssh into your RPi:

ssh pi@raspberrypi.local
(password raspberry)

Open the apt sources file:

sudo nano /etc/apt/sources.list

Uncomment the last line:

deb-src http://archive.raspbian.org/raspbian/ jessie main contrib non-free rpi

Update your system and install some required packages:

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install clang git

Installing Swift 3.0 build at root level. We’re going to use House Dillon’s tarballs:

cd ~
sudo wget http://www.housedillon.com/other/swift-armv7-3.0.tar.gz
sudo tar -xzpf swift-armv7–3.0.tar.gz -C /
rm swift-armv7–3.0.tar.gz

You have installed Swift!! Now start screaming like Steve Ballmer in a moment of uncontrolled excitement.

Let’s write our first Swift script to see that it’s actually working:

mkdir swifttest
cd swifttest
nano main.swift

Add this simple hello world (which ironically doesn’t say “hello world”):

import Glibc
import Foundation
let currentDate = NSDate()
print(“My first Swift binary! Executed at \(now)”)

Compile and run:

swiftc main.swift
./main

Well done! You’re ready for the world. Now go and write beautiful swift code.Or turn some LED on with Swift!

Using Swift to control the Raspberry Pi GPIO pins and turn an LED on

Here we are with a Raspberry Pi with Raspbian and Swift 3.0 installed. Now we can actually do something with it. Like flashing an unsexy LED. But hey, we have to start from somewhere…

Step 1: Understanding the GPIO pins numbers

The core concept is that not all the pins in available on the board are GPIOs (General Purpose Input/Output). Some are power supply, others are ground connection and others are other-stuff.

The number inside the circle is the pin number. Some of these pins match aGPIO pin. For example the pin 7 matches the GPIO4 pin.

We can control only the GPIO pins, not the other ones. The other ones are used to power up your circuit or to do other-stuff.

Step 2: Connecting the circuit

We want to create a simple circuit where an LED is turn on by the GPIO4 (pin 7). So we create a simple circuit like this:

LED + resistor, connected to ground to one side and to a GPIO pin on the other side

Step 3: Making sure we can actually set a value on a GPIO pin

We are installing a package that allow us to set values on a pin from command line. Just to make sure we’re actually able to turn the GPIO value high and low.

sudo apt-get install wiringpi

Now let’s set pin 7 as output and turn it off, then on and then off again:

gpio mode 7 out
gpio write 7 0
gpio write 7 1
gpio write 7 0

It should work. If it doesn’t, well, it’s very likely you’ve made some wiring mistake in your circuit.

Step 4: Using SwiftyGPIO library to control the GPIO pins

Uraimo has created a very nice Swift wrapper around the GPIO pins, so we can control them in our Swift app. There are few things that could be done better (e.g. more protocol oriented representation of the different GPIOs types, better representation of the GPIOs states and more immutability of a GPIO representation), but it’s still a good starting point.

Since the Swift Package Manager is still not working properly on Raspbian to date (July the 8th, 2016), we are going to clone the git repo and use the file directly within our code.

The important bit is to have all the sources in one folder, to be able to compile them all in one simple command.

mkdir ~/ledtest
mkdir ~/ledtest/Sources
cd ~/ledtest
git clone https://github.com/uraimo/SwiftyGPIO.git
cp SwiftyGPIO/Sources/* Sources/

Let’s create our main:

nano Sources/main.swift

with this code:

import Glibc
// Get the Pin where the LED will be attached to
let gpios = SwiftyGPIO.GPIOs(for: .RaspberryPi2)
guard let ledGPIO = gpios[.P4] else {
    fatalError(“It has not been possible to initialised the LED GPIO pin”)
}
// Set the GPIO to output
ledGPIO.direction = .OUT
// Turn on and off the led few times
ledGPIO.value = 1
sleep(1)
ledGPIO.value = 0
sleep(1)
ledGPIO.value = 1
sleep(1)
ledGPIO.value = 0

Now compile and run as super user (it needs sudoer permissions to access the GPIO pins):

swiftc Sources/*.swift
sudo ./main

The LED should blink two times and then stop. Success!!

Step 5: Cleanse our soul with some cleaner code

I feel dirty in writing hacky scripts. I start regretting all my life decisions when I understand I wrote something that’s not even close to be acceptable good. So the following code is the v2 of the app.

But first I really suggest you to configure your Atom or SublimeText editor (on your main computer) to edit code remotely on your RPi, so you don’t have to use nano or vim. (Info for Atom and for SublimeText).

That should be it. Compile and run. The LED should keep blinking until you stop the execution.

This is the basic you need to know to start doing amazing things in electronics with a very nice programming language and all the things that comes with it.


iOS开发下的函数响应式编程

$
0
0

iOS开发下的函数响应式编程

版权说明

本文为刊登于《程序员》杂志2016年5月刊。如需转载,请与《程序员》杂志联系。

背景和面临的问题

随着移动互联网的蓬勃发展,iOS App的复杂度呈指数增长。美团·大众点评两个App随着用户量不断增加、研发工程师数量不断增多,可用性的要求也随之不断提升。在这样的一个背景之下,我们面临了很多的问题和挑战。美团和大众点评的iOS工程师们面对挑战,想出了很多的策略和方针来应对,引入函数响应式编程就是美团App中重要的一环。

函数响应式编程简介

函数式编程想必您一定听过,但响应式编程的说法就不大常见了。与响应式编程对应的命令式编程就是大家所熟知的一种编程范式,我们先来看一段代码:

1
2
3
4
5
6
7
int a = 3;
int b = 4;
int c = a + b;
NSLog(@"c is %d", c); // => 12
a = 5;
b = 7;
NSLog(@"c is %d", c); // 仍然是12

命令式编程就是通过表达式或语句来改变状态量,例如c = a + b就是一个表达式,它创建了一个名称为c的状态量,其值为a与b的加和。下面的a = 5是另一个语句,它改变了a的值,但这时c是没有变化的。所以命令式编程中c = a + b只是一个瞬时的过程,而不是一个关系描述。在传统的开发中,想让c跟随a和b的变化而变化是比较困难的。而让c的值实时等于a与b的加和的编程方式就是响应式编程。

实际上,在日常的开发中我们会经常使用响应式编程的思想来进行开发。最典型的例子就是Excel,当我们在一个B1单元格上书写一个公式“=A1+5”时,便声明了一种对应关系,每当A1单元格发生变化时,单元格B2都会随之改变。

image
图1 Excel中的响应式

iOS开发中也有响应式编程的典型例子,例如Autolayout。我们通过设置约束描述了各个视图的位置关系,一旦其中一个变化,另一个就会响应其变化。类似的例子还有很多。

函数响应式编程(英文Functional Reactive Programming,以下简称FRP,)正是在函数式编程的基础之上,增加了响应式的支持。

简单来讲,FRP是基于异步事件流进行编程的一种编程范式。针对离散事件序列进行有效的封装,利用函数式编程的思想,满足响应式编程的需要。

区别于面向过程编程范式以过程单元作为核心组成部分,面向对象编程范式以对象单元作为核心组成部分,函数式编程范式以函数和高阶函数作为核心组成部分。FRP则以离散有序序列作为核心组成部分,也可将其定义为信号。其特点是具备可迭代特性并且允许离散事件节点有时间联系,计算机科学中称为Monad。

严格意义上来讲,下文提及的iOS开发下的函数响应式编程,并不能算完全的FRP,这一点,本文就不做学术上的讨论了。

接来下会为您介绍iOS相关的FRP内容,我们先从选型开始。

iOS项目的函数响应式编程选型

很长一段时间以来,iOS项目并没有很好的FRP支持,直到iOS 4.0 SDK中增加了Block语法才为函数式编程提供了前置条件,FRP开源库也逐步健全起来。

最先与大家见面的莫过于ReactiveCocoa这样一个库了,ReactiveCocoa是Github在制作Github客户端时开源的一个副产物,缩写为RAC。它是Objective-C语言下FRP思想的一个优秀实例,后续版本也支持了Swift语言。

Swift语言的推出为iOS界的函数式编程爱好者迎来了曙光。著名的FRP开源库Rx系列也新增了RxSwift,保持其接口与ReactiveX.net、RxJava、RxJS接口保持一致。

下面对不同厂商几个版本的FRP库进行简单的对比:

_ Objective-C 支持 Swift 支持 Cocoa框架支持 其他
RAC 2.5 × 完善 迭代周期长,稳定
RAC 3.0+ 继承2.5版本 开始全面支持Swift
RxSwift × 不完善 符合Rx标准

表1 iOS下几种FRP库的对比

美团App由于历史原因仍然沿用ReactiveCocoa 2.5版本。下文也主要会针对ReactiveCocoa 2.5版本做介绍,但各位可以根据自己项目的需要来选择FRP库,其思想和主要的API大同小异。

为什么需要在iOS项目中引入FRP这样厚重的库呢?

iOS的项目主要以客户端项目为主,主要的业务场景就是进行页面交互和与服务器拉取数据,这里面会包含多种事件和异步处理逻辑。FRP本身就是面向事件流的一种开发方式,又擅长处理异步逻辑。所以从逻辑上是满足iOS客户端业务需要的。

然而能够把一个理念融合到实际的项目中,需要一个漫长的过程。所以接下来就根据美团App在FRP上的实践,具体讲述下融入FRP的过程。希望能给大家一些参考。

一步一步进行函数响应式编程

众所周知,FRP的学习是存在一定门槛的,想必这也是大家对FRP、ReactiveCocoa这些概念比较畏惧的主要原因。美团App在推行FRP的过程中,是采用分步骤的形式,逐步演化的。其演化的过程可以分为初探、入门、提高、进阶这样四个阶段。

初探

美团App是在2014年5月第一次将ReactiveCocoa这个开源库纳入到工程中的,当时iOS工程师数量还不是很多,但是已经遇到了写法不统一、代码量膨胀等问题了。

写法不统一聚焦在回调形式的不统一上,iOS中的回调方式有非常多的种类:UIKit主要进行的事件处理target-action、跨类依赖推荐的delegate模式、iOS 4.0纳入的block、利用通知中心(Notifcation Center)进行松耦合的回调、利用键值观察(Key-Value Observe,简称KVO)进行的监听。由于场景不同,选用的规则也不尽相同,并且我们没有办法很好的界定什么场景该写什么样的回调。

这时我们发现ReactiveCocoa这样一个开源库,恰好能以统一的形式来解决跨类调用的问题,也包装了UIKit事件处理、Notifcation Center、KVO等常见的场景。使其代码风格上高度统一。

使用ReactiveCocoa进行统一后,上述的几种回调都可以写成如下形式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 代替target-action
    [[self.confirmButton rac_signalForControlEvents:UIControlEventTouchUpInside]
     subscribeNext:^(id x) {
        // 回调内容写在这里
     }];

// 代替delegate
    [[self.scrollView rac_signalForSelector:@selector(scrollViewDidScroll:) fromProtocol:@protocol(UIScrollViewDelegate)]
     subscribeNext:^(id x) {
        // 回调内容写在这里
     }];

// 代替block
    [[self asyncProcess]
     subscribeNext:^(id x) {
        // 回调内容写在这里
     } error:^(NSError *error) {
        // 错误处理写到这里
     }];

// 代替notification center
    [[[NSNotificationCenter defaultCenter] rac_valuesForKeyPath:@"Some-key" observer:nil]
     subscribeNext:^(id x) {
        // 回调内容写在这里
     }];

// 代替KVO
    [RACObserve(self, userReportString)
     subscribeNext:^(id x) {
        // 回调内容写在这里
     }];

代码1 回调统一

通过观察代码不难发现,ReactiveCocoa使得不同场景下的代码样式上高度统一,使我们在书写代码、维护代码、阅读代码方面的效率大大提高。

经过一定的研究,我们也发现使用RAC(target, key)宏可以更好组织代码形式,利用filter:map:来代替原有的代码,达到更好复用,例如下面两段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 旧写法
    @weakify(self)
    [[self.textField rac_newTextChannel]
     subscribeNext:^(NSString *x) {
         @strongify(self)
         if (x.length > 15) {
             self.confirmButton.enabled = NO;
             [self showHud:@"Too long"];
         } else {
             self.confirmButton.enabled = YES;
         }
         self.someLabel.text = x;

     }];

// 新写法
    RACSignal *textValue = [self.textField rac_newTextChannel];
    RACSignal *isTooLong = [textValue
                            map:^id(NSString *value) {
                                return @(value.length > 15);
                            }];
    RACSignal *whenItsTooLongMessage = [[isTooLong
                                         filter:^BOOL(NSNumber *value) {
                                             return @(value.boolValue);
                                         }]
                                        mapReplace:@"Too long"];
    [self rac_liftSelector:@selector(showHud:) withSignals:whenItsTooLongMessage, nil];
    RAC(self.confirmButton, enabled) = [isTooLong not];
    RAC(self.someLabel, text) = textValue;

代码2 逻辑优化

上述代码修改虽然代码行数有一定的增加,但是结构更加清晰,复用性也做得更好。

综上所述,在这一阶段,我们主要以回调形式的统一为主,不断尝试合适的代码形式来表达绑定这种关系,也寻找一些便捷的小技巧来优化代码。

入门

image
图2 美团App首页

单纯解决回调风格的统一和树立绑定的思维是远远不够的,代码中更大的问题在于共享变量、异步协同以及异常传递的处理。 列举几个简单的场景,就拿美团App的首页来讲,我们可以看到上面包含很多的区块,而各个区块的访问接口不尽相同,但是渲染的逻辑却又多种多样:

  • 有的需要几个接口都返回后才能统一渲染。
  • 有的需要一个接口返回后,根据返回的内容决定后续的接口访问,最终才能渲染。
  • 有的则是几个接口按照返回顺序依次渲染。

这就导致我们在处理这些逻辑的时候,需要很多的异步处理手段,利用一些中间变量来储存状态,每次返回的时候又判断这些状态决定渲染的逻辑。

更糟糕的是,有的时候对于同时请求多个网络接口,某些出现了网络错误,异常处理也变得越来越复杂。

随着对ReactiveCocoa理解的加深,我们意识到使用信号的组合等“高级”操作可以帮助我们解决很多的问题。例如merge:操作可以解决依次渲染的问题,zip:操作可以解决多个接口都返回后再渲染的问题,flattenMap:可以解决接口串联的问题。大概的示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 依次渲染
    RACSignal *mergedSignal = [RACSignal merge:@[[self fetchData1],
                                                 [self fetchData2]]];

// 接口都返回后一起渲染
    RACSignal *zippedSignal = [RACSignal zip:@[[self fetchData1],
                                               [self fetchData3]]];

// 接口串联
    @weakify(self)
    RACSignal *finalSignal = [[self fetchData4]
                              flattenMap:^RACSignal *(NSString *data4Result) {
                                  @strongify(self)
                                  return [self fetchData5:data4Result];
                              }];

没有用到一个中间状态变量,我们通过这几个“魔法接口”神奇地将逻辑描述了出来。这样写的好处还有很多。

FRP具备这样一个特点,信号因为进行组合从而得到了一个数据链,而数据链的任一节点发出错误信号,都可以顺着这个链条最终交付给订阅者。这就正好解决了异常处理的问题。

image
图3 错误传递链

由于此项特性,我们可以不再关注错误在哪个环节,只需等待订阅的时候统一处理即可。我们也找到了很多的方法用来更好地支持异常的处理。例如try:catch:catchTo:tryMap:等。

简单列举下示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 尝试判断并捕捉异常
    RACSignal *signalForSubscriber =

      [[[[[self fetchData1]
          try:^BOOL(NSString *data1,
                    NSError *__autoreleasing *errorPtr) {
              if (data1.length == 0) {
                  *errorPtr = [NSError new];
                  return YES;
              }
              return NO;
          }]
         flattenMap:^RACStream *(id value) {
             @strongify(self)
             return [self fetchData5:value];
         }]
        try:^BOOL(id value,
                  NSError *__autoreleasing *errorPtr) {
            if (![value isKindOfClass:[NSString class]]) {
                *errorPtr = [NSError new];
                return YES;
            }
            return NO;
        }]
       catch:^RACSignal *(NSError *error) {
           return [RACSignal return:error.domain];
       }];

总结一下,在这个阶段,我们主要尝试解决了异步协同的问题,包括了异常的处理。运用了异常处理模型来解决了很多的实际问题,同时继续寻找了更多的技巧来优化代码。

在初探和入门这两个阶段,美团App还只是谨慎地进行小的尝试,主旨是以代码简化为目的,使用ReactiveCocoa这个开源框架的一些便利功能来优化代码。在代码覆盖程度上尽量只在模块内部使用,避免跨层使用ReactiveCocoa。

提高

随着对ReactiveCocoa这个开源框架的理解不断加深。美团App并不满足于简单的尝试,而是开始在更多的场景下使用ReactiveCocoa,并体现一定的FRP思想。这个阶段最具代表性的实践就是与MVVM架构的融合了,它就是体现了FRP响应式的思想。

Model-View-Controller(简称MVC)是苹果Cocoa框架默认的一个架构。实际上业务场景的复杂度越来越高,而MVC架构自身也存在分层不清晰等诸多问题,最终使得MVC这一架构在实际的使用中渐渐走了样。

Model-View-ViewModel(简称MVVM)便是近几年来十分推崇的一种架构,它解决了MVC架构的一些不足,在层次定义上更为清晰。在MVVM的架构中,最为关键的一环莫过于ViewModel层与View层的绑定了,我们的主角FRP恰好可以解决绑定问题,同时还能处理跨层错误处理的问题。

先来关注下绑定,自初探阶段开始,我们就开始使用RAC(target, key)这样的一个宏来表述绑定的关系,并且使用一些简单的信号转换使得原始信号满足视图渲染的需求。在引入MVVM架构后,我们将之前的经验利用起来,并且使用了RACChannel、RACCommand等组件来支持MVVM。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 单向绑定
    RAC(self.someLabel, text) = RACObserve(self.viewModel, someProperty);
    RAC(self.scrollView, hidden) = self.viewModel.someSignal;
    RAC(self.confirmButton, frame) = [self.viewModel.someChannel
                                      map:^id(NSString *str) {
                                          CGRect rect = CGRectMake(0, 0, 0, str.length * 3);
                                          return [NSValue valueWithCGRect:rect];
                                      }];

// 双向绑定
    RACChannelTo(self.someLabel, text) = RACChannelTo(self.viewModel, someProperty);
    [self.textField.rac_newTextChannel subscribe:self.viewModel.someChannel];
    [self.viewModel.someChannel subscribe:self.textField.rac_newTextChannel];
    RACChannelTo(self, reviewID) = self.viewModel.someChannel;

// 命令绑定
    self.confirmButton.rac_command = self.viewModel.someCommand;

    RAC(self.textField, hidden) = self.viewModel.someCommand.executing;
    [self.viewModel.someCommand.errors
     subscribeNext:^(NSError *error) {
         // 错误处理在这里
     }];

绑定只是提供了上层的业务逻辑,更为重要的是,FRP的响应式范式恰如其分地体现在MVVM中。一个MVVM中View就会响应ViewModel的变化。我们来根据一副简单的图来分析一下:

image
图4 MVVM示意图

上述简图列出了View-ViewModel-Model的大致关系,View和ViewModel间通过RACSignal来进行单向绑定,通过RACChannel来进行双向绑定,通过RACCommand进行执行过程的绑定。

ViewModel和Model间通过RACObserve进行监听,通过RACSignal进行回调处理,也可以直接调用方法。

Model有自身的数据业务逻辑,包含请求Web Service和进行本地持久化。

响应式的体现就在于View从一开始就是“声明”了与ViewModel间的关系,就如同A3单元格声明其“=A2+A1”一样。一旦后续数据发生变化,就按照之前的约定响应,彼此之间存在一层明确的定义。View在业务层面也得到了极大简化。

具体的数据流动就如同下图两种形式:

image
image
图5&图6 MVVM的数据流向示意

从两张图中可以看出,无论View收到用户修改TextField的文本框内容的事件,还是受到用户点击Button的事件。View层都不需要对此做特殊的逻辑处理,只是将之传递给ViewModel。而ViewModel自身维护逻辑,并体现在某些绑定关系上。这是与MVC中ViewController和Model的关系是截然不同的。FRP的响应式范式很好的帮助我们实现了此类需求。

之前虽然也提到过错误处理,但是也提到美团App在初探和入门阶段,只是小规模的在模块内使用,对外并不会以RACSignal的形式暴露。而这个阶段,我们也尝试了层级间通过RACSignal来进行信息的传递。这也自然可以应用上FRP异常处理的优势。

image
图7 MVVM的数据流向示意

上图体现了一个按钮绑定了RACCommand收到错误后的一个数据流向。

除了MVVM框架的应用,这个阶段美团App也利用FRP解决另外的一个大问题。那就是多线程。

如果你做过异步拉取数据主线程渲染,那么你一定很熟悉子线程的回调结果转移到主线程的过程。这种操作不但繁琐,重复,关键还容易出错。

RAC提供了很多便于处理多线程的组件,核心类为RACScheduler,使得可以方便的通过subscirbeOn:方法、deliverOn:方法进行线程控制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 多线程控制
    RACScheduler *backgroundScheduler = [RACScheduler scheduler];
    RACSignal *testSignal = [[RACSignal
                             createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
                                 // 本例中,这段代码会确保运行在子线程
                                 [subscriber sendNext:@1];
                                 [subscriber sendCompleted];
                                 return nil;
                             }]
                             subscribeOn:backgroundScheduler];

    [[RACScheduler mainThreadScheduler]
     schedule:^{
        // 这段代码会在下次Runloop时在主线程中运行
         [[testSignal
          deliverOn:[RACScheduler mainThreadScheduler]]
            subscribeNext:^(id x) {
                // 虽然信号的发出者是在子线程中发出消息的
                // 但是接收者确可以确保在主线程接收消息

                // 主线程可以做你想做的渲染工作了!
            }
         ];
     }];

这一个阶段也算是大跃进的一个阶段,随着MVVM的框架融入,跨层的使用RAC使得代码整体使用FRP的比重大幅提高,全员对FRP的熟悉程度和思想的理解也变得深刻了许多。同时也真正使用了响应式的一些思想和特性来解决实际的问题。使其不再是纸上空谈。

我们美团App也在这个阶段挖掘了更多的RAC高级组件,继续代码优化的持续之路。

进阶

美团App的iOS工程师们在大规模使用FRP后,也积蓄了很多的问题。很多小伙伴也问起了,既然是叫FRP,为什么一直体现的都是响应式的思想,对于函数式的思想应用体现似乎不是很明显。虽然FRP是F开头,称为函数响应式编程。但是考虑到函数式编程的复杂性,我们也将函数式编程的优化拿到了进阶这一阶段来尝试。

这一阶段面临的问题是RAC的大规模应用,使得代码中包含了大量的框架性质的代码。例如下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 冗余的代码
    [[self fetchData1]
     try:^BOOL(id value,
               NSError *__autoreleasing *errorPtr) {
         if ([value isKindOfClass:[NSString class]]) {
             return YES;
         }
         *errorPtr = [NSError new];
         return NO;
     }];

    [[self fetchData2]
     tryMap:^id(NSDictionary *value, NSError *__autoreleasing *errorPtr) {
         if ([value isKindOfClass:[NSDictionary class]]) {
             if (value[@"someKey"]) {
                 return value[@"someKey"];
             }
             // 并没有一个名为“someKey”的key
             *errorPtr = [NSError new];
             return nil;
         }
         // 这不是一个Dictionary
         *errorPtr = [NSError new];
         return nil;
     }];

    [[self fetchData3]
     tryMap:^id(NSDictionary *value, NSError *__autoreleasing *errorPtr) {
         if ([value isKindOfClass:[NSDictionary class]]) {
             if (value[@"someOtherKey"]) {
                 return value[@"someOtherKey"];
             }
             // 并没有一个名为“someOtherKey”的key
             *errorPtr = [NSError new];
             return nil;
         }
         // 这不是一个Dictionary
         *errorPtr = [NSError new];
         return nil;
     }];

上述的几个代码段,我们可以看到功能非常近似,内容稍有不同的部分重复出现,很多的同学在实际的开发中也并没有太好地优化它们,甚至很多的同学表示束手无策。这时候函数式编程就可以派上用场了。

函数式编程是一种良好的编程范式,我们在这里主要利用它的几个特点:高阶函数、不变量和迭代。

先来看高阶函数,高阶函数是入参是函数或者返回值是函数的函数。说起来虽然有些拗口,但实际上在iOS开发中司空见惯,例如典型的订阅其实就是一个高阶函数的体现。

1
2
3
4
5
// 高阶函数
    [[self fetchData1]
     subscribeNext:^(id x) {
        // 这是一个block,作为一个参数
     }];

我们更关心的是返回值是函数的函数,这是上面冗长的代码解决之道。代码7的代码中会发现一些相同的逻辑,例如类型判断。我们就可以先做一个这样的小函数:

1
2
3
4
5
6
7
8
typedef BOOL (^VerifyFunction)(id value);

VerifyFunction isKindOf(Class aClass)
{
    return ^BOOL(id value) {
        return [value isKindOfClass:aClass];
    };
}

瞧,很简单对不对!只要把一个类型传进去,就会得到一个用来判断某个对象是否是这个类型的函数。细心的读者会发现我们实际要的是一个入参为对象和一个NSError对象指针的指针类型,返回值是布尔类型的block,但是这个只能返回入参是对象的,显然不满足条件。很多人第一个想到的就是把这个函数改成返回参数为两个参数返回值为布尔类型的block,但是函数式的解决方法是新增一个这样的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
typedef BOOL (^VerifyAndOutputErrorFunction)(id value, NSError **error);

VerifyAndOutputErrorFunction verifyAndOutputError(VerifyFunction verify,
                                                  NSError *outputError)
{
    return ^BOOL(id value, NSError **error) {
        if (verify(value)) {
            return YES;
        }
        *error = outputError;
        return NO;
    };
}

一个典型的高阶函数,入参带有一个block,返回值也是一个block,组合起来就可以把刚才的几个try:代码段优化。可能你会问,为什么要搞成两个呢,一个不是更好?搞成两个的好处就在于,我们可以将任意的VerifyFunction类型的block与一个outputError相结合,来返回一个我们想要的VerifyAndOutputErrorFunction类型block,例如增加一个判断NSDictionary是否包含某个Key的VerifyFunction。下面给出一个优化后的代码,大家可以仔细思考下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// 可以高度复用的函数
typedef BOOL (^VerifyFunction)(id value);

VerifyFunction isKindOf(Class aClass)
{
    return ^BOOL(id value) {
        return [value isKindOfClass:aClass];
    };
}

VerifyFunction hasKey(NSString *key)
{
    return ^BOOL(NSDictionary *value) {
        return value[key] != nil;
    };
}

typedef BOOL (^VerifyAndOutputErrorFunction)(id value, NSError **error);

VerifyAndOutputErrorFunction verifyAndOutputError(VerifyFunction verify,
                                                  NSError *outputError)
{
    return ^BOOL(id value, NSError **error) {
        if (verify(value)) {
            return YES;
        }
        *error = outputError;
        return NO;
    };
}

typedef id (^MapFunction)(id value);

MapFunction dictionaryValueByKey(NSString *key)
{
    return ^id(NSDictionary *value) {
        return value[key];
    };
}

// 与本例关联比较大的函数
typedef id (^MapAndOutputErrorFunction)(id value, NSError **error);
MapAndOutputErrorFunction transferToKeyChild(NSString *key)
{
    return ^id(id value, NSError **error) {
        if (hasKey(key)(value)) {
            return dictionaryValueByKey(key)(value);
        } else {
            *error = [NSError new];
            return nil;
        }
    };
};

- (void)oldStyle
{
    // 冗余的代码
    [[self fetchData1]
     try:^BOOL(id value,
               NSError *__autoreleasing *errorPtr) {
         if ([value isKindOfClass:[NSString class]]) {
             return YES;
         }
         *errorPtr = [NSError new];
         return NO;
     }];

    [[self fetchData2]
     tryMap:^id(NSDictionary *value, NSError *__autoreleasing *errorPtr) {
         if ([value isKindOfClass:[NSDictionary class]]) {
             if (value[@"someKey"]) {
                 return value[@"someKey"];
             }
             // 并没有一个名为“someKey”的key
             *errorPtr = [NSError new];
             return nil;
         }
         // 这不是一个Dictionary
         *errorPtr = [NSError new];
         return nil;
     }];

    [[self fetchData3]
     tryMap:^id(NSDictionary *value, NSError *__autoreleasing *errorPtr) {
         if ([value isKindOfClass:[NSDictionary class]]) {
             if (value[@"someOtherKey"]) {
                 return value[@"someOtherKey"];
             }
             // 并没有一个名为“someOtherKey”的key
             *errorPtr = [NSError new];
             return nil;
         }
         // 这不是一个Dictionary
         *errorPtr = [NSError new];
         return nil;
     }];
}

- (void)newStyle
{

    VerifyAndOutputErrorFunction isDictionary =
      verifyAndOutputError(isKindOf([NSDictionary class]),
                          NSError.new);
    VerifyAndOutputErrorFunction isString =
      verifyAndOutputError(isKindOf([NSString class]),
                         NSError.new);

    [[self fetchData1]
     try:isString];

    [[[self fetchData2]
      try:isDictionary]
      tryMap:transferToKeyChild(@"someKey")];

    [[[self fetchData3]
      try:isDictionary]
     tryMap:transferToKeyChild(@"someOtherKey")];
}

虽然代码有些多,但是从newStyle函数的结果来看,我们在实际的业务代码上非常的简洁,而且还抽离出很多可复用的小函数。在实际的业务中,我们甚至通过这种范式在某些业务场景简化了超过50%的代码量。

除此之外,我们还尝试用迭代来进一步减少临时变量。为什么要减少临时变量呢?因为我们想要遵循不变量原则,这是函数式编程的一个特点。试想下如果我们都是使用一些不变量,就不再会有那么多异步锁和痛苦的多线程问题了。基于以上考虑,我们要求工程师尽量在开发的过程中减少使用变量,从而锻炼用更加函数式的方式来解决问题。

例如下面的简单问题,实现一个每秒发送值为0 1 2 3 … 100的递增整数信号,实现的方法可以是这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- (void)countSignalOldStyle
{
    RACSignal *signal =
    [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        RACDisposable *disposable = [RACDisposable new];
        __block int i = 0;
        __block void (^recursion)();
        recursion = ^{
            if (disposable.disposed || i > 100) {
                return;
            }
            [subscriber sendNext:@(i)];
            ++i;
            [[RACScheduler mainThreadScheduler]
             afterDelay:1 schedule:recursion];
        };
        recursion();
        return disposable;
    }];
}

这样的代码不但用了block自递归,还用了一个闭包的i变量。i变量也在数次递归中进行了修改。代码不易理解且block自递归会存在循环引用。使用迭代和不变量的形式是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (void)countSignalNewStyle
{
    RACSignal *signal =
    [[[[[[RACSignal return:@1]
         repeat] take: 100]
       aggregateWithStart:@0 reduce:^id(NSNumber *running,
                                        NSNumber *next) {
           return @(running.integerValue + next.integerValue);
       }]
      map:^id(NSNumber *value) {
          return [[RACSignal return:value]
                  delay:1];
      }]
     concat];
}

解法是这样的,先用固定返回1的信号生成一个无限重复信号,取前100个值,然后用迭代方法,产生一个递增的迭代,再将发送的密集的递增信号转成一个延时1秒的子信号,最后将子信号进行连接。感兴趣的同学可以自己动手尝试下,也希望大家都去思考不适用变量来解决问题的思路。

这些函数式的写法不仅解决了业务上的问题,也给我们美团App的iOS工程师们开拓了代码优化的新思路。

可以看到,到这一阶段,需要对FRP的理解要求更高。为了追求更好的代码体验,我们朝着FRP的道路又迈进了许多,走到这一步是每一个美团App的iOS工程师共同努力的结果。这是一个尚未完结的阶段,我们的工程师仍然在不选找寻更好的FRP范式。对于开发人员来说,优化之路永远不会停步。

总结

单纯靠这样一篇文章来介绍全部的FRP思想是不可能的,这也仅是起到了抛砖引玉的作用。FRP不仅可以解决项目中实际遇到的很多问题,也能锻炼更好的工程师素养。希望大家能够掌握起来,用FRP的思想来解决更多实际的问题。社区和开源库也需要大家的不断投入。谢谢大家!


细说ReactiveCocoa的冷信号与热信号

$
0
0

细说ReactiveCocoa的冷信号与热信号

版权说明

本文为 美团点评技术团队博客 特供稿件,首发地址在此。如需转载,请与 美团点评技术团队博客 联系。

背景

ReactiveCocoa(简称RAC)是一套基于Cocoa的FRP框架,在我们美团客户端中,我们大量使用了这个框架。而在使用的过程中我们发现,冷信号与热信号的概念很容易混淆并且容易造成一定的问题,相信各位在使用的过程中也可能遇到此类问题。所以我在这里与大家讨论下RAC中冷信号与热信号的相关知识点,希望可以加深大家对冷热信号的理解。

p.s. 以下代码和示例基于ReactiveCocoa v2.5

什么是冷信号与热信号

冷热信号的概念源于C#的MVVM框架Reactive Extensions中的Hot Observables和Cold Observables:

Hot Observables和Cold Observables的区别:

  1. Hot Observables是主动的,尽管你并没有订阅事件,但是它会时刻推送,就像鼠标移动;而Cold Observables是被动的,只有当你订阅的时候,它才会发布消息。
  2. Hot Observables可以有多个订阅者,是一对多,集合可以与订阅者共享信息;而Cold Observables只能一对一,当有不同的订阅者,消息是重新完整发送。

这里面的Observables可以理解为RACSignal。为了加深理解,请大家关注这样的几组代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [subscriber sendNext:@1];
    [subscriber sendNext:@2];
    [subscriber sendNext:@3];
    [subscriber sendCompleted];
    return nil;
}];
NSLog(@"Signal was created.");
[[RACScheduler mainThreadScheduler] afterDelay:0.1 schedule:^{
    [signal subscribeNext:^(id x) {
        NSLog(@"Subscriber 1 recveive: %@", x);
    }];
}];

[[RACScheduler mainThreadScheduler] afterDelay:1 schedule:^{
    [signal subscribeNext:^(id x) {
        NSLog(@"Subscriber 2 recveive: %@", x);
    }];
}];

以上简单的创建了一个信号,并且依次发送@1,@2,@3作为值。下面分别有两个订阅者在不同的时间段进行了订阅,运行的结果如下:

1
2
3
4
5
6
7
2015-08-11 18:33:21.681 RACDemos[6505:1125196] Signal was created.
2015-08-11 18:33:21.793 RACDemos[6505:1125196] Subscriber 1 recveive: 1
2015-08-11 18:33:21.793 RACDemos[6505:1125196] Subscriber 1 recveive: 2
2015-08-11 18:33:21.793 RACDemos[6505:1125196] Subscriber 1 recveive: 3
2015-08-11 18:33:22.683 RACDemos[6505:1125196] Subscriber 2 recveive: 1
2015-08-11 18:33:22.683 RACDemos[6505:1125196] Subscriber 2 recveive: 2
2015-08-11 18:33:22.683 RACDemos[6505:1125196] Subscriber 2 recveive: 3

我们可以看到,信号在18:33:21.681时被创建,18:33:21.793依次接到1、2、3三个值,而在18:33:22.683再依次接到1、2、3三个值。说明了变量名为signal的这个信号,在两个不同时间段的订阅过程中,分别完整的发送了所有的消息。

我们再对这段代码进行一个小的改动:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
RACMulticastConnection *connection = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    [[RACScheduler mainThreadScheduler] afterDelay:1 schedule:^{
        [subscriber sendNext:@1];
    }];

    [[RACScheduler mainThreadScheduler] afterDelay:2 schedule:^{
        [subscriber sendNext:@2];
    }];

    [[RACScheduler mainThreadScheduler] afterDelay:3 schedule:^{
        [subscriber sendNext:@3];
    }];

    [[RACScheduler mainThreadScheduler] afterDelay:4 schedule:^{
        [subscriber sendCompleted];
    }];
    return nil;
}] publish];
[connection connect];
RACSignal *signal = connection.signal;

NSLog(@"Signal was created.");
[[RACScheduler mainThreadScheduler] afterDelay:1.1 schedule:^{
    [signal subscribeNext:^(id x) {
        NSLog(@"Subscriber 1 recveive: %@", x);
    }];
}];

[[RACScheduler mainThreadScheduler] afterDelay:2.1 schedule:^{
    [signal subscribeNext:^(id x) {
        NSLog(@"Subscriber 2 recveive: %@", x);
    }];
}];

稍微有些复杂,我们来一一分析下:

  • 创建了一个信号,在1秒、2秒、3秒分别发送1、2、3这三个值,4秒发送结束信号。
  • 对这个信号调用publish方法得到一个RACMulticastConnection。
  • 将connection进行连接操作。
  • 获得connection的信号。
  • 分别在0.1秒和2秒订阅获得的信号。

抛开RACMulticastConnection是个什么东东,我们先来看下结果:

1
2
3
4
2015-08-12 11:07:49.943 RACDemos[9418:1186344] Signal was created.
2015-08-12 11:07:52.088 RACDemos[9418:1186344] Subscriber 1 recveive: 2
2015-08-12 11:07:53.044 RACDemos[9418:1186344] Subscriber 1 recveive: 3
2015-08-12 11:07:53.044 RACDemos[9418:1186344] Subscriber 2 recveive: 3

首先告诉大家-[RACSignal publish]- [RACMulticastConnection connect]- [RACMulticastConnection signal]这几个操作生成了一个热信号。 我们再来关注下输出结果的一些细节:

  • 信号在11:07:49.943被创建
  • 11:07:52.088时订阅者1才收到2这个值,说明1这个值没有接收到,时间间隔是2秒多
  • 11:07:53.044时订阅者1和订阅者2同时收到3这个值,时间间隔是3秒多

参考一开始的Hot Observables的论述和两段小程序的输出结果,我们可以确定冷热信号的如下特点:

  • 一、热信号是主动的,即使你没有订阅事件,它仍然会时刻推送。(如第二个例子,信号在50秒被创建,51秒的时候1这个值就推送出来了,但是当时还没有订阅者。)而冷信号是被动的,只有当你订阅的时候,它才会发送消息。(如第一个例子。)
  • 二、热信号可以有多个订阅者,是一对多,信号可以与订阅者共享信息(如第二个例子,订阅者1和订阅者2是共享的,他们都能在同一时间接收到3这个值。)而冷信号只能一对一,当有不同的订阅者,消息会从新完整发送。(如第一个例子,我们可以观察到两个订阅者没有联系,都是基于各自的订阅时间开始接收消息的。)

为什么要区分冷信号与热信号

也许你看到这里并且看到这一章节的标题就会有疑问,为什么RAC要搞如此复杂的一个概念,直接搞成一种信号不就好了么?要解释这个问题需要绕一些弯路。(前方可能比较难懂,如果不能很好理解,请自行查阅各类文档。)

最前面提到了RAC是一套基于Cocoa的FRP框架,那就来说说FRP,FRP全写是Functional Reactive Programming,中文译作函数响应式编程,是RP(Reactive Programm,响应式编程)的FP(Functional Programming,函数式编程)实现。说起来很拗口。太多的细节不多讨论,我们先关注下它是FP的情况。

FP有几个很重要的概念是和我们的主题相关的:

纯函数是指一个函数或者一个表达式不存在任何的副作用,就如同数学中的函数:

f(x) = 5x + 1

这个函数在调用的过程中产生除了返回值以外的任何作用,也不受任何外界因素的影响。那么副作用都有哪些呢?我来列举以下几个情况:

  • 函数的处理过程中,修改了外部的变量,例如全局变量。一个特殊点的例子,就是如果把OC的一个方法看做一个函数,所有的成员变量的赋值都是对外部变量的修改。是的,从FP的角度看OOP是充满副作用的。
  • 函数的处理过程中,触发了一些额外的动作,例如发送的全局的一个Notification,在console里面输出的结果,保存了文件,触发了网络,更新的屏幕等。
  • 函数的处理过程中,受到外部变量的影响,例如全局变量,方法里面用到的成员变量。注意block中捕获的外部变量也算副作用。
  • 函数的处理过程中,受到线程锁的影响算副作用。

由此我们可以看出,在目前的iOS编程中,我们是很难的摆脱副作用的。或者换一种说法,我们iOS编程的目的其实是副作用。(基于用户触摸的外界因素,最终反馈到网络变化和屏幕变化上。)

接下来我们来分析下副作用与冷热信号的关系。既然iOS编程中少不了副作用,那么RAC在实际的使用中也不可避免的接触副作用,下面我列举个业务场景,来看下冷信号中副作用的坑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
    self.sessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"http://api.xxxx.com"]];

    self.sessionManager.requestSerializer = [AFJSONRequestSerializer serializer];
    self.sessionManager.responseSerializer = [AFJSONResponseSerializer serializer];

    @weakify(self)
    RACSignal *fetchData = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        @strongify(self)
        NSURLSessionDataTask *task = [self.sessionManager GET:@"fetchData" parameters:@{@"someParameter": @"someValue"} success:^(NSURLSessionDataTask *task, id responseObject) {
            [subscriber sendNext:responseObject];
            [subscriber sendCompleted];
        } failure:^(NSURLSessionDataTask *task, NSError *error) {
            [subscriber sendError:error];
        }];
        return [RACDisposable disposableWithBlock:^{
            if (task.state != NSURLSessionTaskStateCompleted) {
                [task cancel];
            }
        }];
    }];

    RACSignal *title = [fetchData flattenMap:^RACSignal *(NSDictionary *value) {
        if ([value[@"title"] isKindOfClass:[NSString class]]) {
            return [RACSignal return:value[@"title"]];
        } else {
            return [RACSignal error:[NSError errorWithDomain:@"some error" code:400 userInfo:@{@"originData": value}]];
        }
    }];

    RACSignal *desc = [fetchData flattenMap:^RACSignal *(NSDictionary *value) {
        if ([value[@"desc"] isKindOfClass:[NSString class]]) {
            return [RACSignal return:value[@"desc"]];
        } else {
            return [RACSignal error:[NSError errorWithDomain:@"some error" code:400 userInfo:@{@"originData": value}]];
        }
    }];

    RACSignal *renderedDesc = [desc flattenMap:^RACStream *(NSString *value) {
        NSError *error = nil;
        RenderManager *renderManager = [[RenderManager alloc] init];
        NSAttributedString *rendered = [renderManager renderText:value error:&error];
        if (error) {
            return [RACSignal error:error];
        } else {
            return [RACSignal return:rendered];
        }
    }];

    RAC(self.someLablel, text) = [[title catchTo:[RACSignal return:@"Error"]]  startWith:@"Loading..."];
    RAC(self.originTextView, text) = [[desc catchTo:[RACSignal return:@"Error"]] startWith:@"Loading..."];
    RAC(self.renderedTextView, attributedText) = [[renderedDesc catchTo:[RACSignal return:[[NSAttributedString alloc] initWithString:@"Error"]]] startWith:[[NSAttributedString alloc] initWithString:@"Loading..."]];

    [[RACSignal merge:@[title, desc, renderedDesc]] subscribeError:^(NSError *error) {
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error" message:error.domain delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alertView show];
    }];

不晓得大家有没有被这么一大段的代码吓到,我想要表达的是,在真正的工程中,我们的业务逻辑是很复杂的,而一些坑就隐藏在如此看似复杂但是又很合理的代码之下。所以我尽量模拟了一些需求,使得代码看起来更丰富,下面我们还是来仔细看下这段代码的逻辑吧:

  1. 创建了一个AFHTTPSessionManager用来做网络接口的数据获取。
  2. 创建了一个名为fetchData的信号来通过网络获取信息。
  3. 创建一个名为title的信号从获取的data中取得title字段,如果没有该字段则反馈一个错误。
  4. 创建一个名为desc的信号从获取的data中取得desc字段,如果没有该字段则反馈一个错误。
  5. 针对desc这个信号做一个渲染,得到一个名为renderedDesc的新信号,该信号会在渲染失败的时候反馈一个错误。
  6. title信号所有的错误转换为字符串@"Error"并且在没有获取值之前以字符串@"Loading..."占位,之后与self.someLableltext属性绑定。
  7. desc信号所有的错误转换为字符串@"Error"并且在没有获取值之前以字符串@"Loading..."占位,之后与self.originTextViewtext属性绑定。
  8. renderedDesc信号所有的错误转换为属性字符串@"Error"并且在没有获取值之前以属性字符串@"Loading..."占位,之后与self.renderedTextViewtext属性绑定。
  9. titledescrenderedDesc这三个信号的任何错误订阅,并且弹出UIAlertView

看到这里我相信很多熟悉RAC的同学应该是对这些代码表示认同的,它也体现了RAC的一些优势例如良好的错误处理和各种链式处理。但是很遗憾的告诉大家这段代码是有很严重的错误的。

如果你去尝试运行这段代码,并且打开Charles查看,你会惊奇的发现,这个网络请求发送了6次。没错,是6次请求。我们也可以想象到类似的代码在其他副作用的问题,重新刷新了6次屏幕,写入6次文件,发了6个全局通知。

下面来分析下,为什么是6次网络请求呢?首先根据上面的知识,我们可以推断出名为fetchData信号是一个冷信号。那么这个信号在订阅的时候就会执行里面的过程。那这个信号是在什么时候被订阅了呢?仔细回看了代码,我们发现并没有订阅这个信号,只是调用这个信号的flattenMap产生了两个新的信号。

这里有一个很重要的概念,就是任何的信号转换即是对原有的信号进行订阅从而产生新的信号。我们可以写出flattenMap的伪代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- (instancetype)flattenMap_:(RACStream * (^)(id value))block {
{
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
       return [self subscribeNext:^(id x) {
           RACSignal *signal = (RACSignal *)block(x);
           [signal subscribeNext:^(id x) {
               [subscriber sendNext:x];
           } error:^(NSError *error) {
               [subscriber sendError:error];
           } completed:^{
               [subscriber sendCompleted];
           }];
       } error:^(NSError *error) {
           [subscriber sendError:error];
       } completed:^{
           [subscriber sendCompleted];
       }];
    }];
}

除了没有高度复用和缺少一些disposable的处理以外,上述代码可以大致的给我们flattenMap的直观处理,我们可以看到其实是在调用这个方法的时候,生成了一个新的信号,在这个新的信号的执行过程中对self进行的了订阅。我们还需要注意一个细节,就是这个返回信号在未来订阅的时候,才会间接的订阅了self。后续的startWithcatchTo等都可以这样理解。

回到我们的问题,那就是说,在fetchDataflattenMap之后,它就会因为名为titledesc信号的订阅而订阅。而后续我们对desc也进行了flattenMap得到了renderedDesc,那也说明了未来renderedDesc被订阅的时候,fetchData也会被间接订阅。所以我们解释了在后续我们用RAC宏进行绑定的时候,引发的3次fetchData的订阅。由于fetchData是冷信号,所以3次订阅意味着它的过程被执行了3次,也就是网络的3次请求。

另外的3次订阅来自RACSignal类的merge方法。根据上述的描述,我们也可以猜测merge方法也一定是创建了一个新的信号,在这个信号被订阅的时候,把它包含的所有信号订阅。所以我们又得到了额外的3次网络请求。

由此我们可以深刻的看到不熟悉冷热信号对业务造成的影响。我们可以想象对用户流量的影响,对服务器负载的影响,对统计的影响,如果这是一个点赞的接口,会不会造成多次点赞?后果是不堪的。而着一些都可以通过把fetchData转换为热信号来解决。

接下来也许你会问,如果我的整个计算过程中都没有副作用,是否就不会有这个问题,答案是肯定的,试想下刚才那段代码如果没有网络请求,换成一些标准化的计算会怎样。可以肯定的是我们不会出现bug,但是不要忽视的就是其中的运算我们执行了多次。刚才在介绍纯函数的时候,还有一个概念就是引用透明,我们可以在纯函数式语言(例如Haskell)上进行一定的优化,也就是说纯函数的调用在相同参数下的返回值第二次不需要计算,所以在纯函数式语言里面的FRP并没有冷信号的担忧。然而Objective-C语言中并未对纯函数进行优化。所以拥有大规模运算的冷信号对性能也是有一定影响的。

所以如果我们想更好的掌握RAC这个框架,区分冷信号与热信号是十分重要的。

正确理解冷信号与热信号

FRP是一种声明式编程。与传统的命令式编程的区别是声明式只是描述目标性质,让计算机明确目标,而非流程。而声明式编程不一定是FRP所独有的。例如Autolayout就是一种声明式编程的表现,通过编程声明了约束,而框架来做实际的动作。我们的主角RACSignal也是声明式的。请看下面代码:

1
2
3
4
5
6
7
8
9
    RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
      [subscriber sendNext:@1];
        [subscriber sendCompleted];
    }];

    RACSignal *mappedSignal = [signal map:^id(NSNumber *value) {
      return [NSString stringWithFormat:@"Value is %@", value];
    }];

上述代码的声明了一个信号signalsignal指明了发送“1”这个值后发送结束事件。另外声明了一个信号mappedSignalmappedSignal指明signal的值都进行一个字符串的转换。如果仅仅写到这里,sendNext:map:后面的block其实都没有被执行。

那究竟是何时这些block会执行呢?没错,那就是在订阅之后。订阅mappedSignal之后,还会连带的把signal订阅了。因而预先声明的部分就有了动作。

在搞清楚了信号的声明和信号的订阅之后,再来理解多次订阅的问题。既然创建一个信号只是声明了一段操作,那就说明这个信号本身并无状态可言。可以换个角度来理解,在C语言中,声明了一个函数,这个函数在不同的时间被调用了很多次,函数体肯定会执行相应的次数。因为一个被声明的函数并没有状态,它并不清楚自己被谁在什么时间调用。所以冷信号也是一样,这段操作会在每次订阅的时候都执行,因为冷信号没有状态,它并不清楚自己被谁在什么时候订阅了。

当然一旦信号中存在了副作用,等同与一个修改了全局变量的函数,每次执行的时候的效果就是不一样的了,所以才会出现了前面提到的几个问题。

打个比方,冷信号好比一个剧本,它预先把要做的事情约定好。一旦一个导演说开拍,就是订阅了这个剧本,里面说描述的动作也开始一一被执行,而另一个导演拿着这个剧本开拍,显然和这个导演没有什么关系,拍摄的时期也可以不同。但是有可能有略微的关联,那就是演员可能请的相同的(访问相同的外部变量,或者触发网络请求),那可能要穿插着拍戏。另一方面观众可能也是相同的(最终都经过转换被UI订阅),那就会出现观众看两遍相同的剧情。

一旦片子拍好,放到电视上热播,就变成了热信号。它是有状态的,因为所有的观众都共享了播放的时间,大家都在同一时间观看同一片段。所以,把冷信号变为热信号的本质,就是“广播”,“广播”就是我们也在前面的代码中看到了publishRACMulticastConnection这些操作。

另外举个例子,就是视频直播与视频点播。点播是无状态的,你不需要关心别人看了多少,每次你点播后都是从你需要观看的时间开始播放。而直播是有状态的,你必须要在指定的开播时间观看,一旦错过,就没法看漏掉的节目了。

揭示热信号的本质

好的,回到代码的世界。在RAC中,究竟什么才是热信号呢?冷信号比较常见,map一下就会得到一个冷信号。在RAC的世界中,其实所有的热信号都是一个类的,那就是RACSubject。接下来我们来看看究竟它为什么这么“神奇”。

在RAC2.5文档的框架概述中,有这样一段描述:

A subject, represented by the RACSubject class, is a signal that can be manually controlled.

Subjects can be thought of as the “mutable” variant of a signal, much like NSMutableArray is for NSArray. They are extremely useful for bridging non-RAC code into the world of signals.

For example, instead of handling application logic in block callbacks, the blocks can simply send events to a shared subject instead. The subject can then be returned as a RACSignal, hiding the implementation detail of the callbacks.

Some subjects offer additional behaviors as well. In particular, RACReplaySubject can be used to buffer events for future subscribers, like when a network request finishes before anything is ready to handle the result.

在这段描述中,我们可以看出Subject这三个特点:

  1. Subject是“可变”的。
  2. Subject是非RAC到RAC的一个桥梁。
  3. Subject可以良好的附加行为,例如RACReplaySubject可以缓冲事件给未来的订阅者。

从第三个特点来看,Subject具备将事件缓冲给未来订阅者的能力,那也就说明它是自身是有状态的。由此看来Subject是符合热信号的特点的。为了验证它,我们来做个简单实验:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
RACSubject *subject = [RACSubject subject];
RACSubject *replaySubject = [RACReplaySubject subject];

[[RACScheduler mainThreadScheduler] afterDelay:0.1 schedule:^{
    // Subscriber 1
    [subject subscribeNext:^(id x) {
        NSLog(@"Subscriber 1 get a next value: %@ from subject", x);
    }];
    [replaySubject subscribeNext:^(id x) {
        NSLog(@"Subscriber 1 get a next value: %@ from replay subject", x);
    }];

    // Subscriber 2
    [subject subscribeNext:^(id x) {
        NSLog(@"Subscriber 2 get a next value: %@ from subject", x);
    }];
    [replaySubject subscribeNext:^(id x) {
        NSLog(@"Subscriber 2 get a next value: %@ from replay subject", x);
    }];
}];

[[RACScheduler mainThreadScheduler] afterDelay:1 schedule:^{
    [subject sendNext:@"send package 1"];
    [replaySubject sendNext:@"send package 1"];
}];

[[RACScheduler mainThreadScheduler] afterDelay:1.1 schedule:^{
    // Subscriber 3
    [subject subscribeNext:^(id x) {
        NSLog(@"Subscriber 3 get a next value: %@ from subject", x);
    }];
    [replaySubject subscribeNext:^(id x) {
        NSLog(@"Subscriber 3 get a next value: %@ from replay subject", x);
    }];

    // Subscriber 4
    [subject subscribeNext:^(id x) {
        NSLog(@"Subscriber 4 get a next value: %@ from subject", x);
    }];
    [replaySubject subscribeNext:^(id x) {
        NSLog(@"Subscriber 4 get a next value: %@ from replay subject", x);
    }];
}];

[[RACScheduler mainThreadScheduler] afterDelay:2 schedule:^{
    [subject sendNext:@"send package 2"];
    [replaySubject sendNext:@"send package 2"];
}];

按照解读一下上述代码: 1. 0s时创建subjectreplaySubject这两个subject。 2. 0.1s时订阅者1分别订阅了subjectreplaySubject。 3. 0.1s时订阅者2也分别订阅了subjectreplaySubject。 4. 1s时分别向subjectreplaySubject发送了"send package 1"这个字符串作为。 5. 1.1s时订阅者3分别订阅了subjectreplaySubject。 6. 1.1s时订阅者4也分别订阅了subjectreplaySubject。 7. 2s时再分别向subjectreplaySubject发送了"send package 2"这个字符串作为

接下来看一下输出的结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2015-09-28 13:35:22.855 RACDemos[13646:1269269] Start
2015-09-28 13:35:23.856 RACDemos[13646:1269269] Subscriber 1 get a next value: send package 1 from subject
2015-09-28 13:35:23.856 RACDemos[13646:1269269] Subscriber 2 get a next value: send package 1 from subject
2015-09-28 13:35:23.857 RACDemos[13646:1269269] Subscriber 1 get a next value: send package 1 from replay subject
2015-09-28 13:35:23.857 RACDemos[13646:1269269] Subscriber 2 get a next value: send package 1 from replay subject
2015-09-28 13:35:24.059 RACDemos[13646:1269269] Subscriber 3 get a next value: send package 1 from replay subject
2015-09-28 13:35:24.059 RACDemos[13646:1269269] Subscriber 4 get a next value: send package 1 from replay subject
2015-09-28 13:35:25.039 RACDemos[13646:1269269] Subscriber 1 get a next value: send package 2 from subject
2015-09-28 13:35:25.039 RACDemos[13646:1269269] Subscriber 2 get a next value: send package 2 from subject
2015-09-28 13:35:25.039 RACDemos[13646:1269269] Subscriber 3 get a next value: send package 2 from subject
2015-09-28 13:35:25.040 RACDemos[13646:1269269] Subscriber 4 get a next value: send package 2 from subject
2015-09-28 13:35:25.040 RACDemos[13646:1269269] Subscriber 1 get a next value: send package 2 from replay subject
2015-09-28 13:35:25.040 RACDemos[13646:1269269] Subscriber 2 get a next value: send package 2 from replay subject
2015-09-28 13:35:25.040 RACDemos[13646:1269269] Subscriber 3 get a next value: send package 2 from replay subject
2015-09-28 13:35:25.040 RACDemos[13646:1269269] Subscriber 4 get a next value: send package 2 from replay subject

结合结果可以分析出如下内容:

  1. 22.855s时,测试启动,subjectreplaySubject创建完毕。
  2. 23.856s时,距离启动大约1s后,订阅者1订阅者2同时subject接收到了"send package 1"这个值。
  3. 23.857s时,也是距离启动大约1s后,订阅者1订阅者2同时replaySubject接收到了"send package 1"这个值。
  4. 24.059s时,距离启动大约1.2s后,订阅者3订阅者4同时replaySubject接收到了"send package 1"这个值。注意订阅者3订阅者4并没有从subject接收"send package 1"这个值。
  5. 25.039s时,距离启动大约2.1s后,订阅者1订阅者2订阅者3订阅者4同时subject接收到了"send package 2"这个值。
  6. 25.040s时,距离启动大约2.1s后,订阅者1订阅者2订阅者3订阅者4同时replaySubject接收到了"send package 2"这个值。

只关注subject,根据时间线,我们可以得到下图:

RAC冷热信号1

经过观察不难发现,4个订阅者实际上是共享subject的,一旦这个subject发送了值,当前的订阅者就会同时接收到。由于订阅者3订阅者4的订阅者时间稍晚,所以错过了第一次值的发送。这与冷信号是截然不同的反应。冷信号的图类似下图:

RAC冷热信号1

对比上面两张图,是不是可以发现,subject类似“直播”,错过了就不再处理。而signal类似“点播”,每次订阅都会从头开始。所以我们有理由锁定subject天然就是热信号。

下面再来看看replaySubject,根据时间线,我们能得到另一张图:

RAC冷热信号1

将该图与subject那张图对比会发现,订阅者3订阅者4在订阅后马上接收到了“历史值”。对于订阅者3订阅者4来说,他们只关心“历史的值”而不关心“历史的时间线”,因为实际上12是间隔1s发送的,但是他们接收到的显然不是。举个生动的例子,就好像科幻电影里面主人公穿越时间线后会把所有的回忆快速闪过来到现实一样。(见《X战警:逆转未来》、《蝴蝶效应》)所以我们也有理由锁定replaySubject天然也是热信号。

看到这里,我们终于揭开了热信号的面纱,结论便是:

  1. RACSubject及其子类是热信号
  2. RACSignal排除RACSubject类以外的是冷信号

如何将一个冷信号转化成热信号——广播

冷信号与热信号的本质区别在于是否保持状态,冷信号的多次订阅是不保持状态的,而热信号的多次订阅可以保持状态。所以一种将冷信号转换为热信号的方法就是,将冷信号订阅,取得的每一个值再通过RACSbuject发送出去。

看一下下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
RACSignal *coldSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    NSLog(@"Cold signal be subscribed.");
    [[RACScheduler mainThreadScheduler] afterDelay:1.5 schedule:^{
        [subscriber sendNext:@"A"];
    }];

    [[RACScheduler mainThreadScheduler] afterDelay:3 schedule:^{
        [subscriber sendNext:@"B"];
    }];

    [[RACScheduler mainThreadScheduler] afterDelay:5 schedule:^{
        [subscriber sendCompleted];
    }];

    return nil;
}];

RACSubject *subject = [RACSubject subject];
NSLog(@"Subject created.");

[[RACScheduler mainThreadScheduler] afterDelay:2 schedule:^{
    [coldSignal subscribe:subject];
}];

[subject subscribeNext:^(id x) {
    NSLog(@"Subscribe 1 recieve value:%@.", x);
}];

[[RACScheduler mainThreadScheduler] afterDelay:4 schedule:^{
    [subject subscribeNext:^(id x) {
        NSLog(@"Subscribe 2 recieve value:%@.", x);
    }];

执行顺序是这样的:

  1. 创建一个冷信号:coldSignal。该信号声明了“订阅后1.5秒发送‘A’,3秒发送’B’,5秒发送完成事件”。
  2. 创建一个RACSubject:subject
  3. 在2秒后使用这个subject订阅coldSignal
  4. 立即订阅这个subject
  5. 4秒后订阅这个subject

如果所料不错的话,通过订阅这个subject并不会引起coldSignal重复执行block的内容。我们来看下结果:

1
2
3
4
5
2015-09-28 19:36:45.703 RACDemos[14110:1556061] Subject created.
2015-09-28 19:36:47.705 RACDemos[14110:1556061] Cold signal be subscribed.
2015-09-28 19:36:49.331 RACDemos[14110:1556061] Subscribe 1 recieve value:A.
2015-09-28 19:36:50.999 RACDemos[14110:1556061] Subscribe 1 recieve value:B.
2015-09-28 19:36:50.999 RACDemos[14110:1556061] Subscribe 2 recieve value:B.

参考时间线,会得到下图: RAC冷热信号4

解读一下其中的要点: 1. subject是从一开始就创建好的,等到2s后便开始订阅coldSignal。 2. subscribe 1subject创建后就开始订阅的,但是第一个接收时间与subject接收coldSignal第一个值的时间是一样的。 3. subscribe 2subject创建4s后开始订阅的,所以只能接收到第二个值。

通过观察可以确定,subject就是coldSignal转化的热信号。所以使用RACSubject来将冷信号转化为热信号是可行的。

当然,使用这种RACSubject来订阅冷信号得到热信号的方式还是有一些小的瑕疵的。例如subject的订阅者提前终止了订阅,而subject并不能终止对coldSignal的订阅。(RACDisposable是一个比较大的话题,我计划在其他的文章中详细阐述它,也希望感兴趣的同学自己来理解。)所以RAC库中对于冷信号转化成热信号有如下标准的包装:

1
2
3
4
5
- (RACMulticastConnection *)publish;
- (RACMulticastConnection *)multicast:(RACSubject *)subject;
- (RACSignal *)replay;
- (RACSignal *)replayLast;
- (RACSignal *)replayLazily;

这5个方法中,最为重要的就是- (RACMulticastConnection *)multicast:(RACSubject *)subject;这个方法了,其他几个方法也是间接调用它的。我们来看看它的真相:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/// implementation RACSignal (Operations)
- (RACMulticastConnection *)multicast:(RACSubject *)subject {
  [subject setNameWithFormat:@"[%@] -multicast: %@", self.name, subject.name];
  RACMulticastConnection *connection = [[RACMulticastConnection alloc] initWithSourceSignal:self subject:subject];
  return connection;
}

/// implementation RACMulticastConnection

- (id)initWithSourceSignal:(RACSignal *)source subject:(RACSubject *)subject {
  NSCParameterAssert(source != nil);
  NSCParameterAssert(subject != nil);

  self = [super init];
  if (self == nil) return nil;

  _sourceSignal = source;
  _serialDisposable = [[RACSerialDisposable alloc] init];
  _signal = subject;

  return self;
}

#pragma mark Connecting

- (RACDisposable *)connect {
  BOOL shouldConnect = OSAtomicCompareAndSwap32Barrier(0, 1, &_hasConnected);

  if (shouldConnect) {
      self.serialDisposable.disposable = [self.sourceSignal subscribe:_signal];
  }

  return self.serialDisposable;
}

- (RACSignal *)autoconnect {
  __block volatile int32_t subscriberCount = 0;

  return [[RACSignal
      createSignal:^(id<RACSubscriber> subscriber) {
          OSAtomicIncrement32Barrier(&subscriberCount);

          RACDisposable *subscriptionDisposable = [self.signal subscribe:subscriber];
          RACDisposable *connectionDisposable = [self connect];

          return [RACDisposable disposableWithBlock:^{
              [subscriptionDisposable dispose];

              if (OSAtomicDecrement32Barrier(&subscriberCount) == 0) {
                  [connectionDisposable dispose];
              }
          }];
      }]
      setNameWithFormat:@"[%@] -autoconnect", self.signal.name];
}

代码比较短,大概来说明一下: 1. 当RACSignal类的实例调用- (RACMulticastConnection *)multicast:(RACSubject *)subject时,创建一个RACMulticastConnection实例,以selfsubject作为构造参数。 2. RACMulticastConnection构造的时候,保存sourcesubject作为成员变量,创建一个RACSerialDisposable对象。 3. 当RACMulticastConnection类的实例调用- (RACDisposable *)connect这个方法的时候,判断是否是第一次,如果是的话用_signal这个成员变量来订阅sourceSignal之后返回self.serialDisposable;否则直接返回self.serialDisposable。 4. RACMulticastConnectionsignal只读属性,就是热信号,订阅它就可以。它会在- (RACDisposable *)connect第一次调用后,根据sourceSignal的订阅结果来传递事件。 5. 想要确保第一次订阅就能成功订阅sourceSignal,可以使用- (RACSignal *)autoconnect这个方法,它保证了第一个订阅者触发了sourceSignal的订阅,也保证了当返回的信号所有订阅者都关闭连接后sourceSignal被正确关闭连接。

所以,正确的使用可以像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
RACSignal *coldSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    NSLog(@"Cold signal be subscribed.");
    [[RACScheduler mainThreadScheduler] afterDelay:1.5 schedule:^{
        [subscriber sendNext:@"A"];
    }];

    [[RACScheduler mainThreadScheduler] afterDelay:3 schedule:^{
        [subscriber sendNext:@"B"];
    }];

    [[RACScheduler mainThreadScheduler] afterDelay:5 schedule:^{
        [subscriber sendCompleted];
    }];


    return nil;
}];

RACSubject *subject = [RACSubject subject];
NSLog(@"Subject created.");

RACMulticastConnection *multicastConnection = [coldSignal multicast:subject];
RACSignal *hotSignal = multicastConnection.signal;

[[RACScheduler mainThreadScheduler] afterDelay:2 schedule:^{
    [multicastConnection connect];
}];

[hotSignal subscribeNext:^(id x) {
    NSLog(@"Subscribe 1 recieve value:%@.", x);
}];

[[RACScheduler mainThreadScheduler] afterDelay:4 schedule:^{
    [hotSignal subscribeNext:^(id x) {
        NSLog(@"Subscribe 2 recieve value:%@.", x);
    }];
}];

或者这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
RACSignal *coldSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    NSLog(@"Cold signal be subscribed.");
    [[RACScheduler mainThreadScheduler] afterDelay:1.5 schedule:^{
        [subscriber sendNext:@"A"];
    }];

    [[RACScheduler mainThreadScheduler] afterDelay:3 schedule:^{
        [subscriber sendNext:@"B"];
    }];

    [[RACScheduler mainThreadScheduler] afterDelay:5 schedule:^{
        [subscriber sendCompleted];
    }];


    return nil;
}];

RACSubject *subject = [RACSubject subject];
NSLog(@"Subject created.");

RACMulticastConnection *multicastConnection = [coldSignal multicast:subject];
RACSignal *hotSignal = multicastConnection.autoconnect;

[[RACScheduler mainThreadScheduler] afterDelay:2 schedule:^{
    [hotSignal subscribeNext:^(id x) {
        NSLog(@"Subscribe 1 recieve value:%@.", x);
    }];
}];


[[RACScheduler mainThreadScheduler] afterDelay:4 schedule:^{
    [hotSignal subscribeNext:^(id x) {
        NSLog(@"Subscribe 2 recieve value:%@.", x);
    }];
}];

以上的两种写法都可以得到和之前相同的结果。

下面再来看看其他几个方法的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/// implementation RACSignal (Operations)
- (RACMulticastConnection *)publish {
  RACSubject *subject = [[RACSubject subject] setNameWithFormat:@"[%@] -publish", self.name];
  RACMulticastConnection *connection = [self multicast:subject];
  return connection;
}

- (RACSignal *)replay {
  RACReplaySubject *subject = [[RACReplaySubject subject] setNameWithFormat:@"[%@] -replay", self.name];

  RACMulticastConnection *connection = [self multicast:subject];
  [connection connect];

  return connection.signal;
}

- (RACSignal *)replayLast {
  RACReplaySubject *subject = [[RACReplaySubject replaySubjectWithCapacity:1] setNameWithFormat:@"[%@] -replayLast", self.name];

  RACMulticastConnection *connection = [self multicast:subject];
  [connection connect];

  return connection.signal;
}

- (RACSignal *)replayLazily {
  RACMulticastConnection *connection = [self multicast:[RACReplaySubject subject]];
  return [[RACSignal
      defer:^{
          [connection connect];
          return connection.signal;
      }]
      setNameWithFormat:@"[%@] -replayLazily", self.name];
}

这几个方法的时间都相当简单,只是为了简化代码,具体说明一下: 1. - (RACMulticastConnection *)publish就是帮忙创建了RACSubject。 2. - (RACSignal *)replay就是用RACReplaySubject来作为subject,并立即执行connect操作,返回connection.signal。其作用是上面提到的replay功能,既后来的订阅者可以收到历史值。 3. - (RACSignal *)replayLast就是用Capacity为1的RACReplaySubject来替换- (RACSignal *)replaysubject。其作用是使后来订阅者只收到最后的历史值。 4.– (RACSignal)replayLazily– (RACSignal )replay的区别就是replayLazily会在第一次订阅的时候才订阅sourceSignal`。

现在看下之前第二章那个业务场景的例子,其实修改的方法很简单,就是在网络获取的fetchData这个信号后面,增加一个replayLazily变换,就不会出现网络请求重发6次的问题了。

修改后的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
    self.sessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"http://api.xxxx.com"]];

    self.sessionManager.requestSerializer = [AFJSONRequestSerializer serializer];
    self.sessionManager.responseSerializer = [AFJSONResponseSerializer serializer];

    @weakify(self)
    RACSignal *fetchData = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        @strongify(self)
        NSURLSessionDataTask *task = [self.sessionManager GET:@"fetchData" parameters:@{@"someParameter": @"someValue"} success:^(NSURLSessionDataTask *task, id responseObject) {
            [subscriber sendNext:responseObject];
            [subscriber sendCompleted];
        } failure:^(NSURLSessionDataTask *task, NSError *error) {
            [subscriber sendError:error];
        }];
        return [RACDisposable disposableWithBlock:^{
            if (task.state != NSURLSessionTaskStateCompleted) {
                [task cancel];
            }
        }];
    }] replayLazily];  // modify here!!

    RACSignal *title = [fetchData flattenMap:^RACSignal *(NSDictionary *value) {
        if ([value[@"title"] isKindOfClass:[NSString class]]) {
            return [RACSignal return:value[@"title"]];
        } else {
            return [RACSignal error:[NSError errorWithDomain:@"some error" code:400 userInfo:@{@"originData": value}]];
        }
    }];

    RACSignal *desc = [fetchData flattenMap:^RACSignal *(NSDictionary *value) {
        if ([value[@"desc"] isKindOfClass:[NSString class]]) {
            return [RACSignal return:value[@"desc"]];
        } else {
            return [RACSignal error:[NSError errorWithDomain:@"some error" code:400 userInfo:@{@"originData": value}]];
        }
    }];

    RACSignal *renderedDesc = [desc flattenMap:^RACStream *(NSString *value) {
        NSError *error = nil;
        RenderManager *renderManager = [[RenderManager alloc] init];
        NSAttributedString *rendered = [renderManager renderText:value error:&error];
        if (error) {
            return [RACSignal error:error];
        } else {
            return [RACSignal return:rendered];
        }
    }];

    RAC(self.someLablel, text) = [[title catchTo:[RACSignal return:@"Error"]]  startWith:@"Loading..."];
    RAC(self.originTextView, text) = [[desc catchTo:[RACSignal return:@"Error"]] startWith:@"Loading..."];
    RAC(self.renderedTextView, attributedText) = [[renderedDesc catchTo:[RACSignal return:[[NSAttributedString alloc] initWithString:@"Error"]]] startWith:[[NSAttributedString alloc] initWithString:@"Loading..."]];

    [[RACSignal merge:@[title, desc, renderedDesc]] subscribeError:^(NSError *error) {
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error" message:error.domain delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alertView show];
    }];

当然,这样修改,仍然有许多计算上的浪费,例如将fetchData转换为title的block会执行多次,将fetchData转换为desc的block也会执行多次。但是由于这些block都是无副作用的,计算量又小,可以忽略不计。

至此,我们终于揭开RAC中冷信号与热信号的全部面纱,也知道如何使用了。希望此文可以让大家更好的了解RAC,减少使用RAC遇到的误区。谢谢大家。


在 Ubuntu 16.04 Xenial Xerus 上安装 Swift 3.0

$
0
0

作者:Joe,原文链接,原文日期:2016-06-25
译者:小锅;校对:saitjr;定稿:CMB

我们对“让 Swift 3.0 在更多的 Linux 系统上运行”这件事充满了热情,因此我们开始在 Ubuntu 16.04,即 Xenial Xerus,X86 系统上构建 Swift 3.0。安装过程十分简单,只需要添加我们的 APT 仓库,并使用 apt-get 就可以了。二进制文件会被安装到 /opt/swift/swift-3.0 目录下,所以在安装 3.0 版本后需要更新 path 路径。编辑手记:对于我们为什么使用 /opt/swift 而不是 /usr/bin/ 目录,可以在 swift-dev 邮件列表上的这个帖子里面找到原因。

1. 添加仓库密钥

wget -qO- http://dev.iachieved.it/iachievedit.gpg.key | sudo apt-key add -

2. 添加 Xenial 仓库到 source.list 中

echo "deb http://iachievedit-repos.s3.amazonaws.com/ xenial main" | sudo tee --append /etc/apt/sources.list

3. 执行 apt-get update

sudo apt-get update

4. 安装 swift-3.0!

sudo apt-get install swift-3.0

5. 更新 PATH 路径!

export PATH=/opt/swift/swift-3.0/usr/bin:$PATH

6. 测试

git clone https://github.com/apple/example-package-dealer
cd example-packager-dealer
swift build
Compiling Swift Module 'FisherYates' (1 sources)
Linking Library:  .build/debug/FisherYates.a
Compiling Swift Module 'PlayingCard' (3 sources)
Linking Library:  .build/debug/PlayingCard.a
Compiling Swift Module 'DeckOfPlayingCards' (1 sources)
Linking Library:  .build/debug/DeckOfPlayingCards.a
Compiling Swift Module 'Dealer' (1 sources)
Linking Executable:  .build/debug/Dealer

开始执行!

.build/debug/Dealer

FAQ

Q. 这些二进制版本是苹果官方构建的吗?
A. 并不是,我是在自己的个人服务器上构建的,构建过程请参考我之前的文章

Q. 此版本的构建包含了哪些 git 的历史版本?
A. 可以使用 apt-cache show swift-3.0 来查看这些信息。例如:

# apt-cache show swift-3.0
Package: swift-3.0
Conflicts: swift-2.2
Version: 1:3.0-0ubuntu10+xenial1
Architecture: amd64
Installed-Size: 370463
Maintainer: iachievedit (support@iachieved.it)
Depends: clang (>= 3.6), libicu-dev
Homepage: http://dev.iachieved.it/iachievedit/swift
Priority: optional
Section: development
Filename: pool/main/s/swift-3.0/swift-3.0_3.0-0ubuntu10+xenial1_amd64.deb
Size: 72513864
SHA256: b1bf548f353466ea72696089a8b666956a2603edb467eb0517e858eb1ba86511
SHA1: 5dd02b14d21f2e821040de3bb1052561653fcfcd
MD5sum: f2c3d3b9517a303cc86558b6c560a8d6
Description: Open Source Swift
 This is a packaged version of Open Source Swift 3.0 built from
 the following git revisions of the Apple Github repositories:
       Clang:  460d629e85
        LLVM:  8d0086ac3e
       Swift:  1abe85ab41
  Foundation:  4c15543f82
Description-md5: a6b1dd247c7584b61692a101d9d0e5fa

每个构建版本的源码树 (source tree) 都是未经变动的。

Q. 你在上传这些二进制之前有进行过测试吗?
A. Swift 的构建过程就是对二进制文件的测试,之后我会进行一些基本的测试,并且用它来编译我自己的应用,但是我目前并没有单独全面的测试用具。

Q. 你是按一定的日程计划来发布新的构建版本吗?
A. 并不是,不过我是尽量与苹果官方的发布保持同步的。我的目的就是发布这些东西,然后使用大家能够体验并开始在 Linux 上面进行 Swift 开发。

Q. 安装后的文件都在哪里?
A. 所有的文件都放在 /opt/swift/swift-3.0/usr 目录下。

Q. 如何理解包的版本号?
A. 将版本号进行分解,3.0-0ubuntu10+xenial1 可以理解为:

  • 3.0 是 Swift 打包的版本号
  • -0ubuntu10 说明这是 Ubuntu 的第二个包,而开头的 0 代表当前的包不是基于上游的 Debain 包进行改造的。
  • +xenial1 表示这个包是用于 Xenial Xerus 的。

我觉得我的理解是对的,但如果你有别的看法,可以发邮件到 support@iachieved.it 进行探讨。

我们是如何做这些事的

关于如何在 Amazon S3 上面部署 Debain 包仓库,我使用的这份超赞的教程。我曾经试过配置 Launchpad PPA,但是坦白讲,我对部署一个简单的包而需要进行麻烦复杂的元数据整合感到十分厌倦。我能确定对于发行版仓库的部署,这些步骤是必要的,但是对于我需要部署的东西,这显然是杀鸡用牛刀了。对于那些开发 fpm 人们,他们也有一些自己的看法。

我们用来构建代码并且将其上传到仓库的打包脚本可以在 Github 上找到。对于 Swift 3.0,记得切换到 swift-3.0 分支。

本文由 SwiftGG 翻译组翻译,已经获得作者翻译授权,最新文章请访问 http://swift.gg


Viewing all 764 articles
Browse latest View live