The Archive of Interesting Code is an (ambitious) effort on my part to research, intuit, and code up every interesting algorithm and data structure ever invented. In doing so, I hope both to learn the mathematical techniques that power these technologies and to improve my skills as a programmer.
The examples on this site are in a variety of languages. I generally prefer to use C++ for algorithms, since the STL provides a great framework for expressing algorithms that work on a variety of data types. I code up most data structures in Java, both because the Collections framework allows them to be integrated in seamlessly with other applications and because automatic garbage collection simplifies some of the resource management. Every now and then I'll find an algorithm or data structure that is best represented in a different language like Haskell, in which case I'll forgo my usual language conventions.
In case you're curious what I'm someday hoping to having implemented on this page, you can check out my TODO list.
If you're interested in using any of this code in your applications, feel free to do so! You don't need to cite me or this website as a source, though I would appreciate it if you did. However, please don't plagiarize the code here by claiming authorship - that would just be dishonest. I also caution you that while I'm fairly confident that the code on this site is correct, I haven't mercilessly tested every line, and so there may be a lurking bug or two here.
Enjoy!
Name | Link | Date Added | Language | Description |
---|---|---|---|---|
Binomial Heap | (link) | 7‑24‑2010 | C++ | An implementation of a binomial heap data structure for use as a priority queue. |
Bounded Priority Queue | (link) | 7‑24‑2010 | C++ | An implementation of a priority queue with a fixed upper limit to its size.. |
Matrix | (link) | 7‑24‑2010 | C++ | A collection of classes for manipulating matrices. |
VList | (link) | 8‑16‑2010 | Java | An implementation of the List abstraction backed by a VList. |
Function Wrapper | (link) | 8‑16‑2010 | C++ | A C++ wrapper class around unary functions. |
String | (link) | 8‑17‑2010 | C++ | An implementation of a string abstraction that uses the small string optimization. |
nstream | (link) | 8‑31‑2010 | C++ | An stream class that sends and receives data over a network. |
Snake | (link) | 8‑31‑2010 | C++ | An implementation of the game Snake with a rudimentary AI. |
Mergesort | (link) | 9‑14‑2010 | C++ | An implementation of the mergesort algorithm. |
Next Permutation | (link) | 10‑6‑2010 | C++ | An implementation of the nextpermutation STL algorithm. |
Interval Heap | (link) | 10‑17‑2010 | Java | An implementation of a double-ended priority queue using an interval heap. |
Linear-Time Selection | (link) | 10‑18‑2010 | C++ | A deterministic, linear-time selection algorithm using the <a href="http://en.wikipedia.org/wiki/Selection_algorithm#Linear_general_selection_algorithm-Median_of_Medians_algorithm">median-of-medians algorithm. |
Heapsort | (link) | 10‑18‑2010 | C++ | An implementation of the heapsort algorithm. |
Union-Find | (link) | 10‑19‑2010 | Java | An implementation of a disjoint-set data structure using a disjoint set forest. |
Radix Sort | (link) | 10‑19‑2010 | C++ | An implementation of the radix sort algorithm. |
Rational | (link) | 10‑23‑2010 | C++ | A data structure representing a rational number. |
DPLL | (link) | 10‑23‑2010 | Haskell | An implementation of the DPLL algorithm for solving CNF-SAT. |
Smoothsort | (link) | 10‑27‑2010 | C++ | An implementation of the smoothsort algorithm, an adaptive heapsort variant. |
Extendible Array | (link) | 10‑28‑2010 | Java | A dynamic array class with O(1) worst-case runtime lookup and append. |
In-Place Merge | (link) | 10‑29‑2010 | C++ | An implementation of a merge algorithm that runs in-place. |
Random Shuffle | (link) | 10‑29‑2010 | C++ | An algorithm for generating a random permutation of a set of elements. |
Random Sample | (link) | 10‑29‑2010 | C++ | An O(n) time, O(1) space algorithm for randomly choosing k elements out of a stream with uniform probability. |
Natural Mergesort | (link) | 10‑30‑2010 | C++ | An implementation of natural mergesort, an adaptive variant of mergesort. |
Interpolation Search | (link) | 10‑31‑2010 | C++ | An implementation of the interpolation search algorithm. |
Introsort | (link) | 10‑31‑2010 | C++ | An implementation of the introsort algorithm, a fast hybrid of quicksort, heapsort, and insertion sort. |
Hashed Array Tree | (link) | 11‑3‑2010 | Java | An implementation of a dynamic array backed by a hashed array tree. |
Recurrence Solver | (link) | 11‑13‑2010 | C++ | A fast algorithm for generating terms of a sequence defined by a linear recurrence relation. |
Fibonacci Heap | (link) | 11‑15‑2010 | Java | An implementation of a priority queue backed by a Fibonacci heap. |
Dijkstra's Algorithm | (link) | 11‑16‑2010 | Java | An implementation of Dijkstra's algorithm for single-source shortest paths. |
Prim's Algorithm | (link) | 11‑17‑2010 | Java | An implementation of Prim's algorithm for computing minimum spanning trees. |
Kruskal's Algorithm | (link) | 11‑17‑2010 | Java | An implementation of Kruskal's algorithm for computing minimum spanning trees. |
Majority Element | (link) | 11‑17‑2010 | C++ | A fast, linear-time algorithm for finding the majority element of a data set. |
Haar Transform | (link) | 11‑17‑2010 | C++ | A set of functions to decompose a sequence of values into a sum of Haar wavelets. |
Argmax | (link) | 11‑19‑2010 | C++ | A pair of functions to compute the arg min or max of a function on some range. |
Derivative | (link) | 11‑19‑2010 | C++ | A function object that approximates the derivative of a function. |
Levenshtein Distance | (link) | 11‑19‑2010 | C++ | An algorithm for computing the Levenshtein distance between two sequences. |
Skiplist | (link) | 11‑20‑2010 | C++ | An implementation of a skip list, a randomized data structure for maintaining a sorted collection. |
van Emde Boas Tree | (link) | 11‑26‑2010 | C++ | An implementation of a sorted associative array backed by a van Emde Boas tree. |
Cuckoo HashMap | (link) | 11‑27‑2010 | Java | An implementation of a hash table using cuckoo hashing. |
Needleman-Wunsch Algorithm | (link) | 11‑28‑2010 | C++ | An implementation of the Needleman-Wunsch algorithm for optimal string alignment. |
Treap | (link) | 11‑28‑2010 | C++ | An implementation of a sorted associative array backed by a treap. |
Floyd-Warshall Algorithm | (link) | 12‑10‑2010 | Java | An implementation of the Floyd-Warshall algorithm for all-pairs shortest paths in a graph. |
Power Iteration | (link) | 12‑10‑2010 | C++ | An implementation of the power iteration algorithm for finding dominant eigenvectors. |
Edmonds's Matching Algorithm | (link) | 12‑15‑2010 | Java | An implementation of Edmonds's matching algorithm for finding <a href="http://en.wikipedia.org/wiki/Matching(graphtheory)#Maximum_matchings">maximum matchings in undirected graphs. |
Kosaraju's Algorithm | (link) | 12‑15‑2010 | Java | An implementation of Kosaraju's algorithm algorithm for finding strongly connected components of a directed graph. |
2-SAT | (link) | 12‑15‑2010 | Java | A linear-time algorithm for solving 2-SAT. |
Bellman-Ford Algorithm | (link) | 12‑17‑2010 | Java | An implementation of the Bellman-Ford algorithm for single-source shortest paths. |
Topological Sort | (link) | 12‑17‑2010 | Java | An algorithm for computing a topological sort of a directed acyclic graph. |
Graham Scan | (link) | 12‑19‑2010 | C++ | An implementation of the Graham scan for finding convex hulls in 2D space. |
Bipartite Testing | (link) | 12‑19‑2010 | Java | A linear-time algorithm for checking whether a directed graph is bipartite. |
Johnson's Algorithm | (link) | 12‑19‑2010 | Java | An implementation of Johnson's algorithm for all-pairs shortest paths. |
Strassen Algorithm | (link) | 12‑20‑2010 | C++ | An implementation of the Strassen algorithm for fast matrix multiplication. |
Cartesian Tree Sort | (link) | 12‑21‑2010 | C++ | An implementation of Cartesian tree sort, an adaptive, out-of-place heapsort variant. |
Ford-Fulkerson Algorithm | (link) | 12‑21‑2010 | Java | An implementation of the Ford-Fulkerson maximum-flow algorithm. |
Scaling Ford-Fulkerson | (link) | 12‑22‑2010 | Java | An modification of the Ford-Fulkerson maximum-flow algorithm that uses scaling to achieve polynomial time.. |
Splay Tree | (link) | 12‑27‑2010 | C++ | An implementation of a sorted associative array backed by a splay tree. |
Ternary Search Tree | (link) | 12‑28‑2010 | C++ | An implementation of a sorted set of strings backed by a ternary search tree. |
Ring Buffer | (link) | 12‑30‑2010 | Java | An implementation of a FIFO queue using a ring buffer. |
AVL Tree | (link) | 12‑30‑2010 | C++ | A sorted associative container backed by an AVL tree. |
Rabin-Karp Algorithm | (link) | 1‑1‑2011 | C++ | An implementation of the Rabin-Karp algorithm for string matching. |
RPN Evaluator | (link) | 1‑18‑2011 | C++ / strain | A library to tokenize and evaluate simple arithmetic expressions in reverse Polish notation. |
Shunting-Yard Algorithm | (link) | 1‑18‑2011 | C++ / strain | An implementation of Dijkstra's shunting-yard algorithm for converting infix expressions to reverse-Polish notation. |
Skew Binomial Heap | (link) | 1‑20‑2011 | C++ | An implementation of a priority queue backed by a skew binomial heap. |
2/3 Heap | (link) | 3‑1‑2011 | C++ | An implementation of a priority queue whose branching factor alternates at different levels to maximize performance. |
Zeckendorf Logarithm | (link) | 3‑10‑2011 | C++ | An algorithm based on Zeckendorf representations that efficiently computes logarithms. |
Factoradic Permutations | (link) | 3‑17‑2011 | C++ | A set of algorithms for generating permutations using the factoradic number system. |
Binary Cyclic Subsets | (link) | 3‑20‑2011 | C++ | A set of algorithms for generating subsets in lexicographical order using binary numbers and cyclic shifts. |
Fibonacci Iterator | (link) | 3‑22‑2011 | C++ | An STL-style iterator for iterating over the Fibonacci numbers. |
Fibonacci Search | (link) | 3‑22‑2011 | C++ | An implementation of the Fibonacci search algorithm. |
Euclid's Algorithm | (link) | 4‑18‑2011 | Haskell | An implementation of Euclid's algorithm and applications to continued fractions and the extended Euclidean algorithm. |
Find Duplicate | (link) | 4‑18‑2011 | Python | An algorithm to find a repeated element in an array using Floyd's cycle-finding algorithm. |
Permutation Generator | (link) | 4‑19‑2011 | Python | A <a href="http://en.wikipedia.org/wiki/Generator(computerprogramming)">generator for producing all permutations of a list of elements. |
Matrix Find | (link) | 4‑19‑2011 | Python | A solution to the classic interview question of searching a sorted matrix for a particular value. |
Binary GCD | (link) | 4‑23‑2011 | Scheme | An implementation of the binary GCD algorithm for computing greatest common divisors of nonnegative integers. |
Knuth-Morris-Pratt Algorithm | (link) | 5‑3‑2011 | Python | An implementation of the Knuth-Morris-Pratt algorithm for fast string matching. |
Kadane's Algorithm | (link) | 5‑7‑2011 | C++ | An implementation of Kadane's algorithm for solving the maximum-weight subarray problem. |
Karatsuba's Algorithm | (link) | 8‑15‑2011 | Python | An implementation of Karatsuba's algorithm for fast integer multiplication. |
Min-Stack | (link) | 8‑15‑2011 | C++ | An implementation of a <a href="http://en.wikipedia.org/wiki/Stack(datastructure)">LIFO stack that supports O(1) push, pop, and find-minimum. |
Random Bag | (link) | 8‑15‑2011 | Python | A data structure that supports insertion and removal of a uniformly-random element. |
Min-Queue | (link) | 8‑15‑2011 | C++ | An implementation of a <a href="http://en.wikipedia.org/wiki/Queue(datastructure)">FIFO queue that supports O(1) push, pop, and find-minimum. |
Lights-Out Solver | (link) | 8‑29‑2011 | C++ | A solver for the game <a href="http://en.wikipedia.org/wiki/Lights_Out(game)">Lights Out using Gaussian elimination over GF(2). |
Maximum Single-Sell Profit | (link) | 11‑9‑2011 | Python | Four algorithms for the maximum single-sell profit problem, each showing off a different algorithmic technique. |
Generalized Kadane's Algorithm | (link) | 11‑10‑2011 | C++ | A generalization of Kadane's algorithm for solving the maximum subarray problem subject to a length restriction. |
Longest Range | (link) | 11‑19‑2011 | Java | An algorithm for solving the longest contiguous range problem. |
Egyptian Fractions | (link) | 11‑20‑2011 | Python | An implementation of the greedy algorithm for finding Egyptian fractions. |
LL(1) Parser Generator | (link) | 11‑21‑2011 | Java | An LL(1) parser generator. |
LR(0) Parser Generator | (link) | 11‑23‑2011 | Java | An LR(0) parser generator. |
Word Ladders | (link) | 11‑27‑2011 | JavaScript | A program for finding word ladders between two words. |
Alias Method | (link) | 12‑27‑2011 | Java | An implementation of the alias method for sampling from a discrete probability distribution. |
Binary Quicksort | (link) | 1‑5‑2012 | C++ | An implementation of the binary quicksort (binary MSD radix sort) algorithm. |
Ternary Sierpinski Triangle | (link) | 6‑16‑2012 | JavaScript | An algorithm for drawing the Sierpinksi triangle using ternary numbers. |
In-Place Tree Delete | (link) | 12‑12‑2012 | C++ | An algorithm for deleting all of the nodes of a binary tree using O(1) auxiliary storage space. |
Random Access List | (link) | 5‑14‑2013 | Haskell | A purely functional, persistent random-access sequence backed by a random access list. |
BST LCA | (link) | 6‑5‑2013 | Haskell | A function for finding the lowest common ancestor of two nodes in a binary search tree. |
Matrix Fill | (link) | 3‑6‑2014 | Java | An algorithm for solving the matrix fill problem, an interview problem from Microsoft. |
Auther Keith Schwarz 来源 : http://www.keithschwarz.com/interesting/
]]>使用apache的ftp时,在数据量大的时候,在后台会报异常
org.apache.commons.net.ftp.FTPConnectionClosedException: Connection closed without indication.
错误原因大致有三种:
1.FTP服务器服务有故障,或是是网络问题。
解决办法:
1.FTP服务器(这里测试的环境是XP IIS的FTP)的连接数,如果客户端采用多线程访问FTP,可能会 421错误。需要查看连接FTP的Java代码,FTP连接是否已经正常释放掉了,可以考虑将ftp服务端的最大链接数设置大一些。
2.设置的连接超时和数据传输超时值太小。
例如,设置为60秒:
ftpClient.setSocketTimeout(60*000); //设置传输超时时间为60秒
ftpClient.setConnectTimeout(60*000); //连接超时为60秒
apache的默认是-1,即永不超时。如果你没有显式设置超时值,缺省值为-1。
3.有可能是服务器自动断开连接。这种情况需要在程序中使用ftp操作的地方实例化ftpClient,使用过后及时disconnect掉,下次使用再实例化一个ftpClient。其中disconnect建议在try块的finally中使用(防止logout异常而不执行disconnect)。
使用apache的ftp时,在数据量大的时候,在后台会报异常
org.apache.commons.net.ftp.FTPConnectionClosedException: Connection closed without indication.
]]>
下载hadoop源码,可以从官网hadoop.apache.org,或者通过命令:
git clone git://git.apache.org/hadoop-common.git
我下载的是hadoop2.2.0版。
需要maven(安装及配置方法略)来进行编译:
$ mvn install -DskipTests$ mvn eclipse:eclipse -DdownloadSources=true -DdownloadJavadocs=true
接下来可以进行导入了: 选择File中的import...
要说明的是,导入的项目中有无效的引入(有个conf文件夹),可以去掉即可。还有缺少的类(主要是test文件夹中的),可以从对应的项目源码文件中target的对应目录中拷贝过去即可。
现在开始浏览hadoop源码了:)
]]>不过支持的话,也很简单。
首先安装源:
1、rpm --import http://elrepo.org/RPM-GPG-KEY-elrepo.org 2、rpm -Uvh http://elrepo.org/elrepo-release-6-4.el6.elrepo.noarch.rpm 如果你已经有了,那就可以忽略上一步。 接下来: yum install kmod-hfsplus
Ok,插上硬盘看看吧:)
]]>2008-12-18 14:15
如何清晰地思考:近一年来业余阅读的关于思维方面的知识结构整理(附大幅思维导图)
By 刘未鹏(pongba) C++ 的罗浮宫(http://blog.csdn.net/pongba) TopLanguage(https://groups.google.com/group/pongba)
一年前一个偶然的机会我遇到了一本书——《影响力》,看完这本书之后对我们如何思维产生了极大的兴趣,于是在一年的时间里面密集地阅读了以下一些方面的经典著作:社会心理学、认知科学、神经科学、进化心理学、行为经济学、机器学习、人工智能、自然语言处理、问题求解、辩论法(Argumentation Theory)、Critical Thinking、判断与决策。以及大量的 Wikipedia 条目。
这一年来,对以上这些领域的阅读和思考给我带来了极大的价值,我相信他们也会给你带来巨大的收益。 关于为什么我认为我们都需要学习这方面的知识,我曾在博客中写到: 另外还有一些我认为是 essential knowledge 的例子:分析问题解决问题的思维方法(这个东西很难读一两本书就掌握,需要很长时间的锻炼和反思)、判断与决策的方法(生活中需要进行判断与决策的地方远远多于我们的想象),波普尔曾经说过:All Life is Problem-Solving。而判断与决策又是其中最常见的一类Problem Solving。尽管生活中面临重大决策的时候并不多,但另一方面我们时时刻刻都在进行最重大的决策:如:决定自己的日常时间到底投入到什么地方去。如:你能想象有人宁可天天花时间剪报纸上的优惠券,却对于房价的1%的优惠无动于衷吗?(《别做正常的傻瓜》、《Predictably Irrational》)如:你知道为什么当手头股票的股价不可抑止地滑向深渊时我们却一边揪着头发一边愣是不肯撤出吗?(是的,我们适应远古时代的心理机制根本不适应金融市场。)糟糕的判断与决策令我们的生活变得糟糕,这还不是最关键的,最关键的是我们从来不会去质疑自己的判断,而是总是能“找到”其他为自己辩护的理由(《错不在我(Mistakes were made, but not by me)》)又,现在是一个信息泛滥的时代,于是另一个问题也出现:如何在海洋中有效筛选好的信息,以及避免被不好的信息左右我们的大脑(Critical Thinking)关于以上提到的几点我在豆瓣上有一个专门的豆列(“学会思考”),希望有一天我能够积累出足够多的认识对这个主题展开一些详细介绍。
人类的大脑和思维是目前已知最为复杂的系统,对这个系统的研究不仅自身是一件极其迷人的事情,对于像我们这样的芸芸众生来说即便不去做研究,学习一些这方面的科普知识,对于学会正确地思考有极大的益处。
你的大脑是你唯一的工具,要正确利用这个工具,唯一的途径就是去了解它。与很多人的直觉相反,实际上我们的思维有着各种各样的缺陷和陷阱(keyword: cognitive bias),我们解决日常问题的思维方式也并不总是最优的(keyword: bounded rationality),这里摘抄一段我在豆列上的导言: 我们的思维有很多很多的弱点,我一向认为,正确的思维方式,是一切高效学习的基础。比如参见如下2个例子,错误的思维方式得到的结论有大得多的可能性是谬误。
总的来说
以上,构成了人类思维中的种种谬误。而学会思考,就是学会认识到这些谬误。
Critical-Thinking 在西方拥有悠久的历史,早到古希腊时代,亚里士多德就已经对人类语言中的各种各样的谬误有了一定的认识(譬如,“我们无法讨论不存在的东西,所以所有的事物都是真实的”),并对辩论之中存在的各种各样的谬误进行了归类。然而令人遗憾的是,在中国的文化里面,理性思维似乎是一直被抑制的,中国文人传统都是非理性思考者;所谓非理性思考,主要包括联想、比方等形式,这些思维方式作为人类天生具有的思维方式的一种,一方面当然有它的好处(比如在科研方面,联想往往能够启发新思路;类比也有助于用新颖的方式来解决既有问题),然而另一方面,这样的思维方式同样也充满了各种各样致命的谬误。在大众知识领域,自中国古代文人思维习惯流传下来的影响深刻地左右着人们的语言习惯,随处可见的不靠谱的类比和文字游戏就是证明(例如,严格来说,类比的一般形式是,A具有X、Y、Z三个属性,B具有X、Y属性(类似于A),所以B具有Z属性。这个类比要成立,必须要满足一个前提,即X、Y属性对于Z属性的有无必须是有关的。然而这个前提被根本忽视了,详见 False Analogy)。
这个豆列中的书,有一些是介绍人类思维工作的机制的,认识这些机制是正确思考的大前提;有许多是关于人类推理(Reasoning)过程中的形形色色的谬误的,因为唯有认识到 这些谬误,才能避免它们。唯有避免了思维的谬误,才能进行正确的思考。
注:
另:
文章末尾将贴出的是我这一年来学习的知识结构总揽(用XMind画的思维导图)。注:这只是一个整体的知识结构,或者说“寻路图”,其中固然包含一些例子(用 “e.g.” 标出),但最重要的是从各个分支引申出去的延伸阅读,后者包含上百个很有价值的 wikipedia 条目,不下 50 本经典的著作(大部分我已经读过,小部分经过我的仔细考察,正在阅读中或者肯定是有价值的)。
如何获得这些延伸出去的阅读,有两个办法:
以上四个豆列中整理的绝大多数都是我阅读过的,你也可以参考我的整个“思维”标签下的书。如何获得这些书(尤其是其中包含大量的无中文翻译版的英文书)请参考李笑来老师的笔记。
这个领域的新知识是如此的纷至沓来,以至于我只有时间不断地阅读和思考,以及不时在我的 Google Notebook 里做一些笔记,而完全没有时间一本书一本书,一个子领域一个子领域地写具体的 Introduction (目前具体的荐书只是在 TopLanguage 上零散的推荐了几本,还没有专题介绍)。既便如此,仍然还是在博客上写了很多相关的东西,它们就是这一年来的学习的收获的证明:-),因此如果你想快速判断上面列出的一些书籍是否对你有价值,有多大的价值,不妨参考一下我写的这些文章,这些文章很大程度上是在这一年的学习过程当中的感悟或总结。注:第 3 部分(关于学习、记忆与思考)的文章基本上是领域无关的:
关于机器学习的(机器学习和人工智能领域对于理解我们的思维方式也提供了极好的参考)
关于学习、记忆与思考的
好在我并不打算零星的一本一本推荐:D 所以我就花了点时间将整个的知识体系整理了一番,画了下面这张结构图,请按图索骥,如下(有三个版本,1. 至 xMind Share 的超链接,2. 内嵌在该页面中的幻灯片,如果无法载入请参考 1 。3. 图片版(注:图很大,请下载浏览或打印))
我在前面写学习习惯的时候曾经提到:
有朋友问我具体的例子,好吧,那么这张思维导图便是第三点——知识结构——的一个很好的例子:)
至 XMind Share 的超链接:http://share.xmind.net/pongba/how-to-think-straight-4/
嵌入的幻灯片(如加载失败请直接点击上面的 XMind Share 超链接至 XMind 浏览):
图片版(此为缩略版,完整版请至相册下载:google picasa 的 ,或 csdn 相册的)(最后提醒一下,别忘了这幅图只是大量书籍和 Wikipedia 条目的“藏宝图”,如何延伸阅读请参考前文所述的方法) From XMind
2008-12-18 14:15
如何清晰地思考:近一年来业余阅读的关于思维方面的知识结构整理(附大幅思维导图)
By 刘未鹏(pongba) C++ 的罗浮宫(http://blog.csdn.net/pongba) TopLanguage(https://groups.google.com/group/pongba)
一年前一个偶然的机会我遇到了一本书——《影响力》,看完这本书之后对我们如何思维产生了极大的兴趣,于是在一年的时间里面密集地阅读了以下一些方面的经典著作:社会心理学、认知科学、神经科学、进化心理学、行为经济学、机器学习、人工智能、自然语言处理、问题求解、辩论法(Argumentation Theory)、Critical Thinking、判断与决策。以及大量的 Wikipedia 条目。
这一年来,对以上这些领域的阅读和思考给我带来了极大的价值,我相信他们也会给你带来巨大的收益。 ]]>
半年前,JoelOnSoftware和CodingHorror合搞的stackoverflow.com刚上线不久,我兴冲冲地跑过去扔了一个问题:
你们认为编程的首要原则是什么?
作为我的学习原则的一个实践:
5个月过去了,这个问题到现在还有人回复,我得到了一大堆有意思的答案,忍不住翻译过来与大家分享:
DRY – Don’t Repeat Yourself
一点不感到意外吧?
注:DRY原则倒是比较好理解和实践的。但KISS原则则是看上去直白,其实实践起来不那么容易的一个原则,因为simple和stupid的定义并不是每个人、在每个场景下都是一致且明显的,一个人的simple可能是另一个人的stupid,一个人的stupid可能是另一个人的unnecessary。一旦一个标准取决于具体场景,事情就不那么简单了。所以我们经常要说“It depends”。
在这个答案后面有人添加到:
最好设想你的代码会被一个挥着斧头的精神病来维护。
有人接着又YY道:
而且这个挥着斧头的精神病还知道你住在哪儿。 (( 事实上后面有人指出这是 Martin Golding 的一句名言 ))
注:其实这个原则在设计API时也有用:
写API时时刻设想你就是要去使用这坨API的人。
先弄清你的问题是什么!
弄清问题永远是问题解决过程中的第一步和最重要的一步。
代码只是工具,不是手段。
不知道怎么最好地解决你手头的问题(注:需求、架构、算法,技术选型,etc..),写上一万坨代码也是浪费比特。
知道什么时候不该编码。
(类似条目:YAGNI——“你并不需要编写这坨代码!”,针对你的需求编码,“写你所需”,别做“聪明事”,为一个不确定的未来编码。同时也注意模块化设计,以便能在未来新增需求时无痛扩充系统)
永远不要假定你已经了解一切了!
不作没有证据的推论。
想清楚了再编写。类似条目:如果方案在你脑子里面或者纸上不能工作,写成代码还是不能工作。
越懒越好。
过早优化是一切罪恶的根源。
不要重新发明轮子。
测试通过前说什么“它可以工作”都是纯扯淡。
了解你的工具。
一切以用户需求为导向。
利用分治、抽象,解开子问题之间的耦合。
咖啡进,代码出。(Coffee in, Code out) (( 参见 Garbage in, Garbage out. ))
]]>半年前,JoelOnSoftware和CodingHorror合搞的stackoverflow.com刚上线不久,我兴冲冲地跑过去扔了一个问题:
你们认为编程的首要原则是什么?
作为我的学习原则的一个实践:
5个月过去了,这个问题到现在还有人回复,我得到了一大堆有意思的答案,忍不住翻译过来与大家分享:
DRY – Don’t Repeat Yourself
一点不感到意外吧?
注:DRY原则倒是比较好理解和实践的。但KISS原则则是看上去直白,其实实践起来不那么容易的一个原则,因为simple和stupid的定义并不是每个人、在每个场景下都是一致且明显的,一个人的simple可能是另一个人的stupid,一个人的stupid可能是另一个人的unnecessary。一旦一个标准取决于具体场景,事情就不那么简单了。所以我们经常要说“It depends”。
]]>
其实下文的绝大部分内容对所有学习都是同理的。只不过最近在正儿巴经地学算法,而后者又不是好啃的骨头,所以平时思考总结得就自然要比学其它东西要多一些。
问题:目前几乎所有的算法书的讲解方式都是欧几里德式的、瀑布式的、自上而下的、每一个推导步骤都是精准制导直接面向目标的。由因到果,定义、引理、定理、证明一样不少,井井有条一丝不乱毫无赘肉。而实际上,这完全把人类大脑创造发明的步骤给反过来了。看起来是阳关大道,实际上车马不通。
而对读者来说,这就等于直接告诉你答案&做法了,然后让你去验证这个答案&做法是可行&成立的。而关于答案&做法到底是怎么来的,从问题到答案之间经历了怎样的思维过程。却鲜有书能够很好的阐释。就我有限的阅(算法)书经验,除了波利亚的《怎样解题》还算合格之外(也并非最理想),其它的(包括有名的《算法导论》、《如何解题:现代启发式方法》、《Algorithms》、《编程珠玑》,甚至TAOCP——公平地说由于高老大对算法领域历史了解得非常通透,所以许多地方能够从原始脉络来讲述一个问题,譬如令人印象深刻的从竞赛树到堆的讲解就寥寥一页纸道出了堆这个数据结构的本质来,而像刚才列的几本有名的书却都没有做到),在思维的讲述上都算不上合格(当然不是说这些书没有价值,作为知识性的参考书籍,它们将知识整理出系统结构,极大的便利了知识的掌握,就像《什么是数学》所做的工作一样),为什么我这么说呢,因为我发现每每需要寻找对一个算法的解释的时候,翻开这些书,总是直接就看到关于算法逻辑的描述,却看不到整个算法的诞生过程背后的思想。
我们要的不是相对论,而是诞生相对论的那个大脑。我们要的不是金蛋,而是下金蛋的那只鸡。
Update(2008-7-24):* 收到不少同学的批评,想来这个开头对一些著作的语气过重了,实际上,注意,*我完全不否认这些著作的价值,我自己也在通过阅读它们来学习算法,并且有很多收获。这篇文章更多的只是建议除了阅读这些著作之外还需要做的功课。此外,对于这类知识讲述(欧几里德)方式的批判西方(尤其是在数学领域)早就有了,早在欧拉和庞加莱的时候,他们俩就极其强调思维的传授,欧拉认为如果不能传授思维,那数学教学是没意义的。而庞加莱本人则更是对数学思维有极大的兴趣和研究(我前阵子在讨论组上还转载了一篇庞加莱的著名演讲,就是说这个的,参见[这里*](http://groups.google.com/group/pongba/browse_frm/thread/3dfc84e0506486cc))。我只是在说目前的算法书没有做到思维讲述的层面,因此建议阅读这些书之余应该寻找算法的原始出处,应该寻根究底,多做一些功课,知道算法到底是怎么诞生的,并且我说明了为什么应该知其所以然,有哪些好处(见下文),我还给了几个例子譬如红黑树作者讲红黑树的,g9讲后缀树的,以及Knuth讲heap的。唉,其实挺正统的观点,授人以渔,不管是东方西方都有类似的古老谚语。而我只是从认知科学的角度加了点解释,windstorm称之为“解释文”。而已。可惜被开头的语气搞砸了,算了,既发了也就不改了。*
为什么会这样,其实是有原因的。
我们在思考一个问题的过程中有两种思维形式:
既然认识到,人类解决问题的两大思维方式实际上都是有很大的试错成分的(好听一点叫“探索”),那么就不难意识到,对一个问题的思考过程实际上是相当错综复杂的,而且充满了无效分支——在思考的过程中我们也会不断的对分支进行评估,做适当的剪枝——因此当我们找到问题的解之后,一来思维的漫长繁杂的过程已经在大脑里面淡化得差不多了,只有那些引向最终结论的过程会被加“高亮”——我们在思考的过程中本就会不断的抛弃无效的思路,只留下最有希望的思路。简而言之就是最后证明没用或者早先我们就不抱希望的一些想法就被从工作记忆中扔掉了。二来,思考过程是我们的空气和水,而“鱼是最后一个感觉到水的”,我们感觉不到思维法则本身的存在,我们只是不知不觉运用它。三来,由于我们的目标是问题的解,解才是我们为之兴奋和狂喜的东西,而不是求解的过程,过程只是过程,目的才是目的。这就像一个寻宝者,在漫长曲折的寻宝历程之后,在找到宝藏的时候,他会对宝藏感到狂喜(记得阿基米德的“找到了!”吗?)而迫不及待地要展示出来,而漫长的思考本身却成了注脚。我们是有目的的动物,目的达到了,其它的就相对不那么重要了。最后,对于传授知识的人,也许还有其四:感到介绍思维过程是不相干的,毕竟思维过程并不是算法问题的解,算法问题的解才是算法问题的解。然而不幸的是,忽视到达解的那个过程实际上却变成了舍本逐末。我们看到的是寥寥数行精妙绝伦的算法,然后仰天长叹自己想不出来啊想不出来。为什么想不出来,因为你不知道那短短数行算法背后经历的事怎样漫长的思考过程,如果问题求解是一部侦探小说,那么算法只是结局而已,而思考过程才是情节。
既然如此,也就难怪古往今来算法牛人们算法牛,但却没有几个能真正在讲述的时候还原自己的思维过程的(那个“ 渔”字),手把手的教学生走一遍推理的思路,就可以让学生获得思维过程的训练。金出武雄在《像外行一样思考,像专家一样实践》中说写论文应该写得像侦探小说一样,我很赞同。欧几里德式的介绍,除了提供枯燥的知识之外,并没有提供帮助人获得知识的东西——思维(关于对数学书籍的欧几里德式写法的批评其实也是由来已久了,并且有人呼吁了好几种其它的教学方法)。从这方面,我们所尊敬的一些“圣经”级书籍在传道授业上还不如侦探小说,前者是罗列一大堆知识,后者则是阐述获得知识的过程——推理&联想。
然而,我们都是人,人类该有的思维形式,我们难道不是都有吗。既然如此,思维本身又有什么需要一遍遍教的呢?
并非如此。
讲述思维过程而非结果有几个极其重要的价值:
那到底什么样的才算是授人以渔的呢?波利亚的《如何解题》绝对算是一本,他的《数学的发现》也值得一看。具体到算法书,那就不是光看text book就足够的了,为了深入理解一个算法的来龙去脉前因后果,从一个算法中领悟尽量深刻的东西,则需要做到三件事情:
前一段时间我们讨论组上有不少例子,见这里,或这里。 来源: [http://mindhacks.cn/2008/07/07/the-importance-of-knowing-why/](http://mindhacks.cn/2008/07/07/the-importance-of-knowing-why/)
]]>By 刘未鹏(pongba) C++ 的罗浮宫(http://blog.csdn.net/pongba) TopLanguage(https://groups.google.com/group/pongba)
一年前一个偶然的机会我遇到了一本书——《影响力》,看完这本书之后对我们如何思维产生了极大的兴趣,于是在一年的时间里面密集地阅读了以下一些方面的经典著作:社会心理学、认知科学、神经科学、进化心理学、行为经济学、机器学习、人工智能、自然语言处理、问题求解、辩论法(Argumentation Theory)、Critical Thinking、判断与决策。以及大量的 Wikipedia 条目。
这一年来,对以上这些领域的阅读和思考给我带来了极大的价值,我相信他们也会给你带来巨大的收益。
关于为什么我认为我们都需要学习这方面的知识,我曾在博客中写到: 另外还有一些我认为是 essential knowledge 的例子:分析问题解决问题的思维方法(这个东西很难读一两本书就掌握,需要很长时间的锻炼和反思)、判断与决策的方法(生活中需要进行判断与决策的地方远远多于我们的想象),波普尔曾经说过:All Life is Problem-Solving。而判断与决策又是其中最常见的一类Problem Solving。尽管生活中面临重大决策的时候并不多,但另一方面我们时时刻刻都在进行最重大的决策:如:决定自己的日常时间到底投入到什么地方去。如:你能想象有人宁可天天花时间剪报纸上的优惠券,却对于房价的1%的优惠无动于衷吗?(《别做正常的傻瓜》、《Predictably Irrational》)如:你知道为什么当手头股票的股价不可抑止地滑向深渊时我们却一边揪着头发一边愣是不肯撤出吗?(是的,我们适应远古时代的心理机制根本不适应金融市场。)糟糕的判断与决策令我们的生活变得糟糕,这还不是最关键的,最关键的是我们从来不会去质疑自己的判断,而是总是能“找到”其他为自己辩护的理由(《错不在我(Mistakes were made, but not by me)》)又,现在是一个信息泛滥的时代,于是另一个问题也出现:如何在海洋中有效筛选好的信息,以及避免被不好的信息左右我们的大脑(Critical Thinking)关于以上提到的几点我在豆瓣上有一个专门的豆列(“学会思考”),希望有一天我能够积累出足够多的认识对这个主题展开一些详细介绍。
人类的大脑和思维是目前已知最为复杂的系统,对这个系统的研究不仅自身是一件极其迷人的事情,对于像我们这样的芸芸众生来说即便不去做研究,学习一些这方面的科普知识,对于学会正确地思考有极大的益处。
你的大脑是你唯一的工具,要正确利用这个工具,唯一的途径就是去了解它。与很多人的直觉相反,实际上我们的思维有着各种各样的缺陷和陷阱(keyword: cognitive bias),我们解决日常问题的思维方式也并不总是最优的(keyword: bounded rationality),这里摘抄一段我在豆列上的导言: 我们的思维有很多很多的弱点,我一向认为,正确的思维方式,是一切高效学习的基础。比如参见如下2个例子,错误的思维方式得到的结论有大得多的可能性是谬误。
总的来说
以上,构成了人类思维中的种种谬误。而学会思考,就是学会认识到这些谬误。
Critical-Thinking 在西方拥有悠久的历史,早到古希腊时代,亚里士多德就已经对人类语言中的各种各样的谬误有了一定的认识(譬如,“我们无法讨论不存在的东西,所以所有的事物都是真实的”),并对辩论之中存在的各种各样的谬误进行了归类。然而令人遗憾的是,在中国的文化里面,理性思维似乎是一直被抑制的,中国文人传统都是非理性思考者;所谓非理性思考,主要包括联想、比方等形式,这些思维方式作为人类天生具有的思维方式的一种,一方面当然有它的好处(比如在科研方面,联想往往能够启发新思路;类比也有助于用新颖的方式来解决既有问题),然而另一方面,这样的思维方式同样也充满了各种各样致命的谬误。在大众知识领域,自中国古代文人思维习惯流传下来的影响深刻地左右着人们的语言习惯,随处可见的不靠谱的类比和文字游戏就是证明(例如,严格来说,类比的一般形式是,A具有X、Y、Z三个属性,B具有X、Y属性(类似于A),所以B具有Z属性。这个类比要成立,必须要满足一个前提,即X、Y属性对于Z属性的有无必须是有关的。然而这个前提被根本忽视了,详见 False Analogy)。
这个豆列中的书,有一些是介绍人类思维工作的机制的,认识这些机制是正确思考的大前提;有许多是关于人类推理(Reasoning)过程中的形形色色的谬误的,因为唯有认识到 这些谬误,才能避免它们。唯有避免了思维的谬误,才能进行正确的思考。
注:
另:
文章末尾将贴出的是我这一年来学习的知识结构总揽(用 XMind 画的思维导图)。注:这只是一个整体的知识结构,或者说“寻路图”,其中固然包含一些例子(用 “e.g.” 标出),但最重要的是从各个分支引申出去的延伸阅读,后者包含上百个很有价值的 wikipedia 条目,不下 50 本经典的著作(大部分我已经读过,小部分经过我的仔细考察,正在阅读中或者肯定是有价值的)。
如何获得这些延伸出去的阅读,有两个办法:
以上四个豆列中整理的绝大多数都是我阅读过的,你也可以参考我的整个“思维”标签下的书。如何获得这些书(尤其是其中包含大量的无中文翻译版的英文书)请参考李笑来老师的笔记。
这个领域的新知识是如此的纷至沓来,以至于我只有时间不断地阅读和思考,以及不时在我的 Google Notebook 里做一些笔记,而完全没有时间一本书一本书,一个子领域一个子领域地写具体的 Introduction (目前具体的荐书只是在 TopLanguage 上零散的推荐了几本,还没有专题介绍)。既便如此,仍然还是在博客上写了很多相关的东西,它们就是这一年来的学习的收获的证明:-),因此如果你想快速判断上面列出的一些书籍是否对你有价值,有多大的价值,不妨参考一下我写的这些文章,这些文章很大程度上是在这一年的学习过程当中的感悟或总结。注:第 3 部分(关于学习、记忆与思考)的文章基本上是领域无关的:
关于机器学习的(机器学习和人工智能领域对于理解我们的思维方式也提供了极好的参考)
关于学习、记忆与思考的
好在我并不打算零星的一本一本推荐:D 所以我就花了点时间将整个的知识体系整理了一番,画了下面这张结构图,请按图索骥,如下(有三个版本,1. 至 xMind Share 的超链接,2. 内嵌在该页面中的幻灯片,如果无法载入请参考 1 。3. 图片版(注:图很大,请下载浏览或打印))
我在前面写学习习惯的时候曾经提到:
有朋友问我具体的例子,好吧,那么这张思维导图便是第三点——知识结构——的一个很好的例子:)
至 XMind Share 的超链接:http://share.xmind.net/pongba/how-to-think-straight-4/
嵌入的幻灯片(如加载失败请直接点击上面的 XMind Share 超链接至 XMind 浏览):
图片版(此为缩略版,完整版请至相册下载:google picasa 的 ,或 csdn 相册的)(最后提醒一下,别忘了这幅图只是大量书籍和 Wikipedia 条目的“藏宝图”,如何延伸阅读请参考前文所述的方法) From XMind
消息:TopLanguage 最近经历了一次很大的管理策略修订,可以预期将彻底摆脱这两个月来的噪音问题,未来的讨论质量将会越来越高。详情可参见这里。 来源: [http://blog.csdn.net/pongba/article/details/3549560](http://blog.csdn.net/pongba/article/details/3549560)
]]>好的管理者都是好的时间管理者。而管理者时间管理的根本是抓大放小、果断决策、大胆授权、梳理系统、做好计划。只有这样,管理者才能防范偷走你宝贵时间的5大窃贼,才能让自己免于焦头烂额。
管理者管理什么?一是管事,二是管人,三是管时间。在这三个维度上,管事最容易,管人最困难,管时间不难却最容易被忽略。
很多管理者天天忙得团团转,却得不到上司的好评,主要的原因就是不会做时间管理,让自己和下属宝贵的时间被浪费掉。
什么会偷走管理者的时间,让管理者焦头烂额却得不到应得的结果?以我的经验,管理者有5大时间窃贼需要提防。
抓小放大。很多管理者忙于无数的小细节,不跳出细节思考什么才是自己真正应该做的事情。结果是不重要的事情做了一大堆,重要的事情一个没有做,上司不关心的事情做了一大堆,上司关心的事情一个没有做。其实事情都有逻辑关系和层次:解决一个上一级的问题,通常能让你一下子解决3〜5个次一级的问题。如果我们能抓住最上级的问题用心解决,解决一个最上级问题的效果会相当于解决几十个最底层级的问题。但解决一个大问题和解决一个小问题花的时间差别并不大,至少不是几十倍的差别。
议而不决。很多管理者忙于开会,忙于和很多相关和不相关的同事讨论如何解决一个问题,却迟迟不愿自己负起责任做出决定。这类管理者把本来可以半个小时开完的会议拖延到3个小时,把本来可以在一次会议上做的决定延迟到下一次会议。议而不决的后果是让管理者要处理的事情大量积压,让管理者的时间越来越少。这样的管理者没有认识到,没有事情可以通过拖延得到解决,决策的质量也不能通过拖延得到提高。
不能授权。很多管理者习惯于自己做事情,不习惯授权给别人做,总担心别人做不好,总觉得教会别人做不如自己做快。久而久之,自己做的小事越来越多,自己的时间越来越不够用,身边的人越来越闲,自己的委屈越来越多。
管而不理。很多管理者习惯于管事,不习惯于理事。例如,发现有人迟到,会狠狠地批评当事人,却不会思考是否是公司的考勤制度或考勤技术有问题。管而不理的后果是,一件事情发生一次,管理者要管一次,次次发生,次次要管。随着企业规模的扩大,次次管的事情会大幅增加,管理者的时间越来越少。其实只要系统梳理一次,一类问题就能解决了。从这个角度看,管是小,理是大,管理者要抓大放小,就要更多地梳理,而不是被动地管理。
不做计划。计划是什么?就是把你要做的事情和你可以用的资源合理地匹配起来,简而言之就是事先想清楚在什么时间用什么资源完成你要做的事情。在可以用的资源里,最重要的和最稀少的资源就是时间了。不做计划意味着资源和事情不匹配,意味着资源尤其是时间资源的浪费。一个人一天就24小时,浪费了就没有了。很多人忙,其实不是没有时间,而是没有合理地安排时间。
好的管理者都是好的时间管理者。而管理者时间管理的根本是抓大放小、果断决策、大胆授权、梳理系统、做好计划。只有这样,管理者才能防范偷走你宝贵时间的5大窃贼,才能让自己免于焦头烂额。
分享是一种美德,请随手转播
敬请关注【流程管理】公众微信平台,微信号:e8flow,宣传流程管理理念,每日会与您分享管理技巧,管理经验、哲理小故事和财经评论、财经观点。 您可以通过 “添加朋友”--> "搜索号码" 或 “查找公众微信账号”,输入 e8flow ,搜索添加此关注
]]>好的管理者都是好的时间管理者。而管理者时间管理的根本是抓大放小、果断决策、大胆授权、梳理系统、做好计划。只有这样,管理者才能防范偷走你宝贵时间的5大窃贼,才能让自己免于焦头烂额。
管理者管理什么?一是管事,二是管人,三是管时间。在这三个维度上,管事最容易,管人最困难,管时间不难却最容易被忽略。
]]>2012年12月28日 陈皓
每年一到要找工作的时候,我就能收到很多人给我发来的邮件,总是问我怎么选择他们的offer,去腾讯还是去豆瓣,去外企还是去国内的企业,去创业还是去考研,来北京还是回老家,该不该去创新工场?该不该去thoughtworks?……等等,等等。今年从7月份到现在,我收到并回复了60多封这样的邮件。我更多帮他们整理思路,帮他们明白自己最想要的是什么。(注:我以后不再回复类似的邮件了)。
我深深地发现,对于我国这样从小被父母和老师安排各种事情长大的人,当有一天,父母和老师都跟不上的时候,我们几乎完全不知道怎么去做选择。而我最近也离开了亚马逊,换了一个工作。又正值年底,就像去年的那篇《三个故事和三个问题》一样,让我想到写一篇这样的文章。
当我们在面对各种对选择的影响因子的时候,如:城市,公司规模,公司性质,薪水,项目,户口,技术,方向,眼界…… 你总会发现,你会在几个公司中纠结一些东西,举几个例子:
某网友和我说,他们去上海腾讯,因为腾讯的规模很大,但却发现薪水待遇没有豆瓣高(低的还不是一点),如果以后要换工作的话,起薪点直接关系到了以后的高工资。我说那就去豆瓣吧,他说豆瓣在北京,污染那么严重,又没有户口,生存环境不好。我说去腾讯吧,他说腾讯最近组织调整,不稳定。我说那就去豆瓣吧,慢公司,发展很稳当。他说,豆瓣的盈利不清楚,而且用Python,自己不喜欢。我说,那就去腾讯吧,……
还有一网友和我说,他想回老家,因为老家的人脉关系比较好,能混得好。但又想留在大城市,因为大城市可以开眼界。
另一网友和我说,他想进外企,练练英语,开开眼界,但是又怕在外企里当个螺丝钉,想法得不到实施。朋友拉他去创业,觉得创业挺好的,锻炼大,但是朋友做的那个不知道能不能做好。
还有一网友在创新工场的某团队和考研之间抉择,不知道去创新工场行不行,觉得那个项目一般,但是感觉那个团队挺有激情的,另一方面觉得自己的学历还不够,读个研应该能找到更好的工作。
还有一些朋友问题我应该学什么技术?不应该学什么技术?或是怎么学会学得最快,技术的路径应该是什么?有的说只做后端不做前端,有的说,只做算法研究,不做工程,等等,等等。因为他们觉得人生有限,术业有专攻。
等等,等等……
我个人觉得,如果是非计算机科班出生的人不会做选择,不知道怎么走也罢了,但是我们计算机科班出生的人是学过算法的,懂算法的人应该是知道怎么做选择的。
你不可能要所有的东西,所以你只能要你最重要的东西,你要知道什么东西最重要,你就需要对你心内的那些欲望和抱负有清楚的认识,不然,你就会在纠结中度过。
所以,在选择中纠结的人有必要参考一下排序算法。
首先,你最需要参考的就是“冒泡排序”——这种算法的思路就是每次冒泡出一个最大的数。所以,你有必要问问你自己,面对那些影响你选择的因子,如果你只能要一个的话,你会要哪个?而剩下的都可以放弃。于是,当你把最大的数,一个一个冒泡出来的时候,并用这个决策因子来过滤选项的时候,你就能比较容易地知道知道你应该选什么了。这个算法告诉我们,人的杂念越少,就越容易做出选择。
好吧,可能你已茫然到了怎么比较两个决策因子的大小,比如:你分不清楚,工资>业务前景吗?业务前景>能力提升吗?所以你完全没有办法进行冒泡法。那你,你不妨参考一个“快速排序”的思路——这个算法告诉我们,我们一开始并不需要找到最大的数,我们只需要把你价值观中的某个标准拿出来,然后,把可以满足这个价值的放到右边,不能的放到左边去。比如,你的标准是:工资大于5000元&&业务前景长于3年的公司,你可以用这个标准来过滤你的选项。然后,你可以再调整这个标准再继续递归下去。这个算法告诉我们,我们的选择标准越清晰,我们就越容易做出选择。
这是排序算法中最经典的两个算法了,面试必考。相信你已烂熟于心中了。所以,我觉得你把这个算法应用于你的人生选择也应该不是什么问题。关于在于,你是否知道自己想要的是什么?
排序算法的核心思想就是,让你帮助你认清自己最需要的是什么,认清自己最想要的是什么,然后根据这个去做选择。
所谓贪婪算法,是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择(注意:是当前状态下),从而希望导致结果是最好或最优的算法。贪婪算法最经典的一个例子就是哈夫曼编码。
对于人类来说,一般人在行为处事的时候都会使用到贪婪算法,
比如在找零钱的时候,如果要找补36元,我们一般会按这样的顺序找钱:20元,10元,5元,1元。
或者我们在过十字路口的时候,要从到对角线的那个街区时,我们也会使用贪婪算法——哪边的绿灯先亮了我们就先过到那边去,然后再转身90度等红灯再过街。
这样的例子有很多。对于选择中,大多数人都会选用贪婪算法,因为这是一个比较简单的算法,未来太复杂了,只能走一步看一步,在当前的状况下做出最利于自己的判断和选择即可。
有的人会贪婪薪水,有的人会贪婪做的项目,有的人会贪婪业务,有的人会贪婪职位,有的人会贪婪自己的兴趣……这些都没什么问题。贪婪算法并没有错,虽然不是全局最优解,但其可以让你找到局部最优解或是次优解。其实,有次优解也不错了。贪婪算法基本上是一种急功近利的算法,但是并不代表这种算法不好,如果贪婪的是一种长远和持续,又未尝不可呢?。
但是我们知道,对于大部分的问题,贪婪法通常都不能找出最优解,因为他们一般没有测试所有可能的解。因为贪婪算法是一种短视的行为,只会跟据当前的形式做判断,也就是过早做决定,因而没法达到最佳解。
动态规划和贪婪算法的最大不同是,贪婪算法做出选择,不能回退。动态规划则会保存以前的运算结果,并根据以前的结果对当前进行选择,有回退功能。
动态规划算法至少告诉我们两个事:
1)承前启后非常重要,当你准备去做遍历的时候,你的上次的经历不但能开启你以后的经历,而且还能为后面的经历所用。你的每一步都没有浪费。
2)是否可以回退也很重要。这意思是——如果你面前有两个选择,一个是A公司一个是B公司,如果今天你错失了B公司,那到你明天还能不能找回来?
比如说:你有两个offer,一个是Yahoo,一个是Baidu,上述的第一点会让我们思考,Yahoo和Baidu谁能给我们开启更大的平台?上述的第二点告诉我们,是进入Yahoo后如果没有选好,是否还能回退到Baidu公司?还是进入Baidu公司后能容易回退到Yahoo公司?
最短路径是一个Greedy + DP的算法。相当经典。这个算法的大意如下:
1)在初始化的时候,所有的结点都和我是无穷大,默认是达不到的。
2)从离自己最近的结点开始贪婪。
3)走过去,看看又能到达什么样的结点,计算并更新到所有目标点的距离。
4)再贪婪与原点最短的结点,如此反复。
这个算法给我们带来了一些这样的启示:
有朋友和我说过他想成为一个架构师,或是某技术领域的专家,并会踏踏实实的向这个目标前进,永不放弃。我还是鼓励了他,但我也告诉他了这个著名的算法,我说,这个算法告诉你,架构师或某领域的专家对你来说目前的距离是无穷大,他们放在心中,先看看你能够得着的东西。所谓踏实,并不是踏踏实实追求你的目标,而是踏踏实实把你够得着看得见的就在身边的东西干好。我还记得我刚参加工作,从老家出来的时候,从来没有想过要成为一个技术牛人,也从来没有想过我的博客会那么的有影响力,在做自己力所能及,看得见摸得着的事情,我就看见什么技术就学什么,学着学着就知道怎么学更轻松,怎么学更扎实,这也许就是我的最短路径。
有很多朋友问我要不要学C++,或是问我学Python还是学Ruby,是不是不用学前端,等等。这些朋友告诉我,他们不可能学习多个语言,学了不用也就忘了,而且术业有专攻。这并没有什么不对的,只是我个人觉得,学习一个东西没有必要只有两种状态,一种是不学,另一种是精通。了解一个技术其实花不了多少时间,我学C++的目的其实是为了更懂Java,学TCP/IP协议其实是为了更懂Socket编程,很多东西都是连通和相辅相成的,学好了C/C++/Unix/TCP等这些基础技术后,我发现到达别的技术路径一下缩短了(这就是为什么我用两天时间就可以了解Go语言的原因)。这就好像这个算法一样,算法效率不高,也许达到你的目标,你在一开始花了很长时间,遍历了很多地方,但是,这也许这就是你的最短路径。
你根本没有办法能得到所有你想得到的东西,任何的选择都意味着放弃——当你要去获得一个东西的时候,你总是需要放弃一些东西。人生本来就是一个跷跷板,一头上,另一头必然下。这和我们做软件设计或算法设计一样,用时间换空间,用空间换时间,还有CAP理论,总是有很多的Trade-Off,正如这个短语的原意一样——你总是要用某种东西去交易某种东西。
我们都在用某种东西在交易我们的未来,有的人用自己的努力,有的人用自己的思考,有的人用自己的年轻,有的人用自己的自由,有的人用自己的价值观,有的人用自己的道德…… …… 有的人在交换金钱,有的人在交换眼界,有的人在交换经历,有的人在交换地位,有的人在交换能力,有的人在交换自由,有的人在交换兴趣,有的人在交换虚荣心,在交换安逸享乐…… ……
每个人有每个人的算法,每个算法都有每个算法的purpose,就算大家在用同样的算法,但是每个人算法中的那些变量、开关和条件都不一样,得到的结果也不一样。我们就是生活在Matrix里的一段程序,我们每个人的算法决定着我们每个人的选择,我们的选择决定了我们的人生。
2012年就要过去了,祝大家新年快乐!
插图来自电影 Life of Pi
(全文完)
(转载本站文章请注明作者和出处 酷壳 – CoolShell.cn ,请勿用于任何商业用途)
]]>2012年12月28日 陈皓
每年一到要找工作的时候,我就能收到很多人给我发来的邮件,总是问我怎么选择他们的offer,去腾讯还是去豆瓣,去外企还是去国内的企业,去创业还是去考研,来北京还是回老家,该不该去创新工场?该不该去thoughtworks?……等等,等等。今年从7月份到现在,我收到并回复了60多封这样的邮件。我更多帮他们整理思路,帮他们明白自己最想要的是什么。(注:我以后不再回复类似的邮件了)。
我深深地发现,对于我国这样从小被父母和老师安排各种事情长大的人,当有一天,父母和老师都跟不上的时候,我们几乎完全不知道怎么去做选择。而我最近也离开了亚马逊,换了一个工作。又正值年底,就像去年的那篇《三个故事和三个问题》一样,让我想到写一篇这样的文章。
]]>
本文作者:叶正盛,阿里巴巴数据库技术专家,专注于数据库应用性能量化。
再次写给我们这些刚入行浮躁的程序员,如何成长,以下是列出了一些成长的心得,我们不必每条都去实践,但是优秀的程序员成长过程中总会实践里面的几条。
多做项目,多思考
不要害怕做事,刚毕业的同学最缺的就是工作经验,乱七八糟的项目能让你很快就了解了一个公司的业务与使用的技术,并且可以多接触同事与客户。
当你毕业后刚进一家公司时,如果主管没有把你安排到项目组工作,那真的很杯具,因为他认为你还不能胜任工作或者你的加入会让项目组更糟。
还有人说,我刚进公司,公司就把我当成了苦工,工资又低,项目组加入好几个,也做了很多事情,每天都要加班。我估计有很多人感觉是这种状态,为什么会是这样,因为全国人民(不只是程序员)里有90%可能都和你一样的感觉,这说明你现在状况是很普遍的,也说明你现在的能力并没有很多出众的地方。也许是逆境才能让人成长,如果有一天你让你的团队从这些苦力工作中解脱出来或者能给你的团队前进的动力,那你就升华了,你就比他们出众。你没有能力去改变现状,所以只能接受,而不要认为是自己生不逢时,或者说公司环境太差。创业也一样,不要认为公司没发展的主要原因是环境太差,那你不要去当老板算了,投资环境都非常好还能轮到你吗。
还有很多同学感觉自己付出了很多,回报太少,这个问题很难平衡,首先一点,公司在聘你进来后不会因为你没有成绩就先给你回报,公司也不可能会在你有了成绩后就立即给你回报,但是长时间付出没有回报,那这个公司就不值得你付出。我不赞成频繁换公司,这么做至少可以说明你是一个只求回报不求付出的人。
至于薪资的问题,这个很难去评估,因为每个企业的收益相差太远。但是刚毕业的同学工作需要关注薪资+成长环境,当薪资可以满足普通生活需求后,成长环境更为重要,就好比,给你一月5000元,或者6000元,真的不那么重要,因为这些收入在你以后的人生中基本没有影响。当然,如果你现在在大城市几年里每个月只拿着1000元,那还是需要选择一下收入更好的公司,因为这么低的收入会严重影响你的工作学习计划,也说明你的公司不重视员工,没有能力给员工好生活的公司,将来的发展也是有限的。
特别说明一点,互联网公司与传统信息化企业不一样,互联网一直是风险比较高的行业,也许你选择了一个看好的企业,也佩服老板的眼光,可能你现在需要的是与公司同甘共苦。不要指望在刚创业的团队里拿到非常好的待遇,因为你现在就是在投资,也许几年后公司成功了,你就是功臣,不怎么出色的你也可以当上总监或副总裁。
自己开发框架与工具来提高工作效率
当你参与了很多项目,当你发现自己经常做一些COPY,PASTE的操作时,你可以考虑花时间去提取问题的共性,做一些自动化工具去摆平问题,或者是写一些基础框架来屏蔽这些无聊并且累赘的代码。
自己开发框架与工具,可以让你快速的从一个初级程序员转变成更高级的程序员或分析师或架构师,因为这个过程中给你提供了为其他程序员服务的机会,你有动力去了解其它程序员的工作需求,你可以把你的框架或工具写得很好,接口简单灵活并且性能好,分析师和架构师就经常要干这种让人力成本降低的事。但要记住一点,不要以为自己开发框架与工具就认为很NB了,因为这种工作并不会体现多少技术含量,而只是提高个人抽象问题的能力,这个活很多程序员都能干,但是很少人去干好。
参与开源项目
参与开源项目可以让你领略到不同程序员的沟通方法,开发习惯,技术思维,可以认识更多的朋友,如果你足够强,也可能一举成名哦。可以让你更深入了解这个开源东西,所以最好是感兴趣或者是与工作有关的,不要说什么流行就参与什么。开源项目可以自己贡献一个新的项目,或者参与一个感兴趣的项目。
不要指望开源项目会给你带来直接的金钱,如果你想拿着开源项目封装一下去发财,那我真不知道如何做,可以去问问什么什么芯,什么什么国产操作系统的人,他们更有经验。
英语
在这个全球信息时代,英语真的是一个很重要的工具,我真的很羡慕那些学校里英语就很好的同学,好的英语能力可以更快速的了解到更多知识。当前,新的技术与知识大部份语言都是英语或翻译成英语,如果能把英语学好,可以让你人生少奋斗10年。
写技术博客
写技术博客是一种可以快速提高的方法,但是一个人能坚持每周写技术博客,那是需要付出很多代价,写博客并不是要我们写出高质量的文章才发表,我们可以分享自己的一些小经验,也可以分享自己的体会。一样东西在你大脑里,并不表示你已经掌握了,如果你能说给别人听,或者用文字表达出来,那首先你要将这些知识点整理清楚才好表达。我经常认为自己已经对某个问题了解了,但是在整理技术博客时发现自己的知识盲点,然后再去查找知识来补充自己的盲点,直到最后搞清楚了才算告一段落。
有些人不喜欢分享或者害怕分享,但是在这个世界,只要不是公司机密或商业秘密,拿出来分享可以让你得到更多同行的反馈,网络上的人会给你相对真实的反馈,因为大部份人与你没有利益关系。
新人不要害怕自己分享的知识是否有技术含量,只要你认为有价值,都可以拿出来,这不仅可以给别人提供知识,也可以自己整理思路,还可以得到网友的反馈。如果你的知识没有价值,分享出来也没有关系,如果你的文章技术含量低,怕被人鄙视,那是你这个人不敢承认现实,因为同事与朋友可能不会说你的文章很菜,就算被鄙视了又如何,有时被人鄙视也是一种前进的动力。有人说如果几年后我进步了很多,但还让人看到我这些初学时弱智的文档,误人子弟,不好意思,Ok,那个时候有可以完全把文档删除,其实我更喜欢放在那里品味自己成长的过程,把有误导的地方更正。
我知道有一个技术博客作者,数据库专家杨廷琨(http://yangtingkun.itpub.net/),他几年来,每天坚持写一篇技术博客,现在已经有2千多篇,我的ORACLE数据库水平比他差很多,但是我也偶尔看到一些他新写的文档我几年前就会了,但这些并不妨碍我对这位博客作者的敬佩,因为他的博客让我学到了很多知识。
加入感兴趣的技术论坛
每个公司使用的技术与产品及环境都不太一样,也许你在公司里感觉什么东西都是别人做好了,我只是个流水线工人,我们的系统由于有严格的规范也不太出问题,自己的实践提高机会太少,那建议你加入感兴趣的技术论坛。
技术论坛上你可以看到很多人各种各样的问题与分享讨论,你也可以试着去帮别人解决问题。技术论坛可以让你进一步成长,但不要告诉我你只是会沙发、顶或接分的那种。
国内CSDN、OSCHINA、ITPUB、CHINAUNIX、JAVAEYE都是人气很旺,里面也不缺技术大牛与无敌大菜鸟。
常看参考手册
很多程序员,遇到问题喜欢直接去请教别人,或是Google找结果,通过别人或Google也许问题可以解决,但是只能形成知识点,不能形成知识体系。
要全面掌握一个东西最快的方法是看产品的官方参考手册,参考手册一般是代表正规的用法或者是推荐的用法,对于小产品最好是先将参考手册全部看一遍。如果是比较大的产品如(ORACLE、JAVA、.NET)那可以选择看经常使用到的部分。只有当你在看完参考手册还不懂的时候再去Google或与别人探讨,这样的方式会让你的知识更体系化。
深入分析问题原因
程序员一定要具备对技术问题刨根问底的想法,很多程序员能解决问题,但是不想去了解问题的根源。我们经常遇到问题,而且很多问题重启程序或者重启机器就好了,有多少程序员会去挖掘重启就解决问题的原因。我是从事数据库的,也经常看到很多人遇到数据库有问题,重装一下搞定,而没有深入分析问题产生的原因。也许在生产环境我们没有时间去分析,但是在开发环境、测试环境你是不是也经常重启解决问题。如果能在开发环境与测试环境遇到问题,这是技术人员成长的最好机会,我们在自己的领域一定不能放过这种成长的机会,因为大部份专家都是在这种历练中出来的。
不要害怕复杂
很多程序员习惯了利用各种框架及工具解决问题,自己只是写一些简单逻辑,当有一天遇到一个问题,没有对应的框架或工具时就放弃需求。我们不要害怕困难,如果你每天的代码都没有挑战,那何来提高,我们应该在适当的时候给自己一些压力,这样可以让自己提高得更快一些。比如你的系统需要一个轻量级的工作流引擎、编译器、解析器、界面设计器、屏幕控制器,或者一个http服务器之类的东东,但是现有的东西都感觉不太满意,你可以自己去搞一个试试,不要害怕不成功,不要害怕自己做不好。这些东西看起来有点复杂,但是当你深入去做时,你会发现里面有很多有意思的东西,你需要去逐步改进你的小系统,直到它能很好的运行为止,这是个很好的成长过程,可以让你对程序有更深的理解,也可打开思路。
学习计算机基础,深入技术原理
有时候我们经常迷惘,感觉技术水平没有提高,感觉技术能力总是浮在表面,特别是当你发现自己算法分析、性能分析、故障诊断能力有限时,也许这是你再次需要学习计算机基础的时候,因为基础不牢,所以你的问题诊断准确率不高。每个程序员应该都学过计算机基础(计算机体系、操作系统、网络、数据库原理、算法等等),这些知识对很多人来说是很枯燥。在当前高级编程语言时代,你的计算机基础不好也能编码,而且效率也不低,但是当你要想成为技术牛人,计算机基础就是一道坎,因为不扎实的计算机基础知识会让你在忽悠与被忽悠中成长。
关心产品市场与商业动态
程序员是否需要关心产品市场与商业动态,我认为是有必要的,除非你真是技术天才,能闭关十年后横扫江湖。计算机技术发展太快,每年都有新的流行产品与技术,大公司也经常改变战略或易主。如果你想引领技术潮流,想创业,那一定要关心产品市场与商业动态。
不要去轻视任何一种职位、语言、工具
在IT岗位里,没有高低之分,不要去轻视任何一种岗位,有些程序员认为自己的成果最有价值,美工、测试只是边缘岗位,项目经理就只会瞎指挥,不干活,销售人员与售前人员接到定单后屁事都没有,整个项目基本上就是我一个人的成果。这种心态是最要不得的。其实你的领导并不会这么想,很多事情是你不知道的,如客户关系就可能不是你一个人搞定的。还有最重要的一点,如果这个项目没有你参加怎么样?项目可能换成另外一个人做,也许他也能做得也不错,这就说明你的价值或重要性并不像你想象的那么重要。举个例子:
就好比你买一台联想电脑4000块,卖给一个没看过电脑的火星人20000块,这台电脑是最后的成果,但是否表示联想这台电脑是最重要的,可能你买一台戴尔的电脑还赚的钱更多,也可能你只要给对方一台杂牌电脑就可以拿到20000块。在这个例子里更重要的也许是客户关系与抓住商机,而买什么样的电脑影响不大(你在项目里的地位可能就是这台电脑的作用,没有你肯定不完整,但是很容易找到你的替代品,所以你的价值并不是最重要的)。
计算机编程语言是初学者最喜欢对比的话题,有的大师也经常对比各种语言的优缺点。我并不反对的评论那种语言的优劣,但我们不能去鄙视某种语言的及其使用者,因为流行的语言都有它生存的环境,可能是我们对技术的见识太窄,也可能是我们对人类的思维习惯了解的不全面,不要总是拿自己的习惯去评价。有很多系统管理员喜欢用命令行,喜欢用shell,perl等脚本语言,这些东西在我看来简直是低效且易读性差的东西,但是当你经常在没有图形界面下工作时,脚本语言可能真是更高效的选择。
最后写上一句浮躁的根源:
不要把祖国当母亲,应该把祖国当自己的孩子。
本不想讲这句话的,但是现实就是如此,浮躁的人群总是对社会充满了意见。我认为所有的这些浮躁都有一个共同点,就是认为自己无法改变这个社会,改变这个社会是国家的事,是其他人的事。
小时候老师总是讲祖国是母亲,我们是花朵,但是实际上我们也不是什么花朵,我们就是郑智化歌里的那根“小小的草,风吹雨打后依然不倒”。现实的社会总是充满着种种不平衡,但是浮躁并不能解决问题。有时总在想祖国并不像我的母亲,她更像是我的孩子,她还很小,经历过很多坎坷,我们经常感觉自家的孩子比不上别人的孩子的某个方面,于是对孩子多加责骂,也可能会让她花一个暑假的时间去补习。小孩子有一些成绩后也会骄傲,有时还会欺骗,我们不能容忍的是她的恶意谎言,但是她还没有到无药可救的程度,她依然还在成长。我们经常拿孩子与别人的孩子对比,而且总是发现别人孩子更好的一面,但是你是否希望与别人交换孩子呢,除了感情外你是否了解别人孩子的全部,我们需要更多的面对现实,应该在孩子成长的时候及时指出她的缺点,她不可能什么都是优秀的,所以我们应该尽自己的能力让她更好一些。你不太可能改变母亲,但是你的行动会影响孩子,你抛弃孩子,你真正的孩子将来可能也会抛弃你,所以说祖国可能并不像母亲,更像孩子,如果你把祖国当孩子,也许是另一种人生价值。 来源: [http://www.oschina.net/question/5189_20311](http://www.oschina.net/question/5189_20311)
]]>本文作者:叶正盛,阿里巴巴数据库技术专家,专注于数据库应用性能量化。
再次写给我们这些刚入行浮躁的程序员,如何成长,以下是列出了一些成长的心得,我们不必每条都去实践,但是优秀的程序员成长过程中总会实践里面的几条。
多做项目,多思考
不要害怕做事,刚毕业的同学最缺的就是工作经验,乱七八糟的项目能让你很快就了解了一个公司的业务与使用的技术,并且可以多接触同事与客户。
当你毕业后刚进一家公司时,如果主管没有把你安排到项目组工作,那真的很杯具,因为他认为你还不能胜任工作或者你的加入会让项目组更糟。
还有人说,我刚进公司,公司就把我当成了苦工,工资又低,项目组加入好几个,也做了很多事情,每天都要加班。我估计有很多人感觉是这种状态,为什么会是这样,因为全国人民(不只是程序员)里有90%可能都和你一样的感觉,这说明你现在状况是很普遍的,也说明你现在的能力并没有很多出众的地方。也许是逆境才能让人成长,如果有一天你让你的团队从这些苦力工作中解脱出来或者能给你的团队前进的动力,那你就升华了,你就比他们出众。你没有能力去改变现状,所以只能接受,而不要认为是自己生不逢时,或者说公司环境太差。创业也一样,不要认为公司没发展的主要原因是环境太差,那你不要去当老板算了,投资环境都非常好还能轮到你吗。
还有很多同学感觉自己付出了很多,回报太少,这个问题很难平衡,首先一点,公司在聘你进来后不会因为你没有成绩就先给你回报,公司也不可能会在你有了成绩后就立即给你回报,但是长时间付出没有回报,那这个公司就不值得你付出。我不赞成频繁换公司,这么做至少可以说明你是一个只求回报不求付出的人。
至于薪资的问题,这个很难去评估,因为每个企业的收益相差太远。但是刚毕业的同学工作需要关注薪资+成长环境,当薪资可以满足普通生活需求后,成长环境更为重要,就好比,给你一月5000元,或者6000元,真的不那么重要,因为这些收入在你以后的人生中基本没有影响。当然,如果你现在在大城市几年里每个月只拿着1000元,那还是需要选择一下收入更好的公司,因为这么低的收入会严重影响你的工作学习计划,也说明你的公司不重视员工,没有能力给员工好生活的公司,将来的发展也是有限的。
特别说明一点,互联网公司与传统信息化企业不一样,互联网一直是风险比较高的行业,也许你选择了一个看好的企业,也佩服老板的眼光,可能你现在需要的是与公司同甘共苦。不要指望在刚创业的团队里拿到非常好的待遇,因为你现在就是在投资,也许几年后公司成功了,你就是功臣,不怎么出色的你也可以当上总监或副总裁。
]]>EN文:
Computing Thoughts A Career in Computing by Bruce Eckel June 2, 2009 Summary I regularly receive requests for career advice, and I've tried to capture the answers in this blog, and in a follow-on. For those of you who asked but never got an answer, I apologize. Your questions stimulated me to work on this, and it's taken awhile.
The question that people ask is usually the wrong one: "should I learn C++ or Java?" In this essay, I shall try to lay out my view of the true issues involved in choosing a career in computing.
Note that I am not talking here to the people who already know it is their calling. You're going to do it regardless of what anyone says, because it's in your blood and you can't get away from it. You know the answer already: C++ AND Java AND shell scripting AND Python AND a host of other languages and technologies that you'll learn as a matter of course. You already know several of these languages, even if you're only 14.
The person who asks me this question may be coming from another career. Or perhaps they are coming from a field like web development and they've figured out that HTML is only kind of like programming, and they'd like to try building something more substantial. But I especially hope that, if you are asking this question, you've realized that to be successful in computing, you need to teach yourself how to learn, and never stop learning.
The more I do this, the more it seems to me that software is more akin to writing than anything else. And we haven't figured out what makes a good writer, we only know when we like what someone writes. This is not some kind of engineering where all we have to do is put something in one end and turn the crank. It is tempting to think of software as deterministic -- that's what we want it to be, and that's the reason that we keep coming up with tools to help us produce the behavior we desire. But my experience keeps indicating the opposite, that it is more about people than processes, and the fact that it runs on a deterministic machine becomes less and less of an influence, just like the Heisenberg principle doesn't affect things on a human scale.
My father built custom homes, and in my youth I would occasionally work for him, mostly doing grunt labor and sometimes hanging sheet rock. He and his lead carpenter would tell me that they gave me these jobs for my own good -- so that I wouldn't go into the business. It worked.
So I can also use the analogy that building software is like building a house. We don't refer to everyone who works on a house as if they were exactly the same. There are concrete masons, roofers, plumbers, electricians, sheet rockers, plasterers, tile setters, laborers, rough carpenters, finish carpenters, and of course, general contractors. Each of these requires a different set of skills, which requires a different amount of time and effort to acquire. House-building is also subject to boom and bust cycles, like programming. If you want to get in quick, you might take a job as a laborer or a sheet rocker, where you can start getting paid without much of a learning curve. As long as demmand is strong, you have steady work, and your pay might even go up if there aren't enough people to do the work. But as soon as there's a downturn, carpenters and even the general contractor can hang the sheet rock themselves.
When the Internet was first booming, all you had to do was spend some time learning HTML and you could get a job and earn some pretty good money. When things turned down, however, it rapidly becomes clear that there is a hierarchy of desirable skills, and the HTML programmers (like the laborers and sheet rockers) go first, while the highly-skilled code smiths and carpenters are retained.
What I'm trying to say here is that you don't want to go into this business unless you are ready to commit to lifelong learning. Sometimes it seems like programming is a well-paying, reliable job -- but the only way you can make sure of this is if you are always making yourself more valuable.
Of course you can find exceptions. There are always those people who learn one language and are just competent enough and perhaps savvy enough to stay employed without doing much to expand their abilities. But they are surviving by luck, and they are ultimately vulnerable. To make yourself less vulnerable, you need to continuously improve your abilities, by reading, going to user groups, conferences, and seminars. The more depth you have in this field, the more valuable you will be, which means you have more stable job prospects and can command higher salaries.
Another approach is to look at the field in general, and find a place where you already have talents. For example, my brother is interested in software, and dabbles with it, but his business is in installing computers, fixing them and upgrading them. He's always been meticulous, so when he installs or fixes your computer you know that it will be in excellent shape when he's done; not just the software, but all the way down to the cables, which will be bundled neat and out of the way. He's always had more work than he could do, and he never noticed the dot-com bust. And needless to say, his work cannot be offshored.
I stayed in college a long time, and managed to get by in various ways. I even began a Ph.D. program at UCLA, which was mercifully cut short -- I say mercifully because I no longer loved being in college, and the reason I stayed in college for so long was because I enjoyed it so much. But what I enjoyed was typically the off-track stuff. Art and dance classes, working on the college newspaper, and even the handful of computer programming classes that I took (which were off-track because I was a physics undergrad and a computer engineering graduate student). Although I was far from exceptional academically (a delightful irony is that many colleges that would not have accepted me as a student now use my books in their courses!), I really enjoyed the life of the college student, and had I finished a Ph.D. I probably would have taken the easy path and ended up a professor.
But as it turns out, some of the greatest value that I got from college was from those same off-track courses, the ones that expanded my mind beyond "stuff we already know." I think this is especially true in computing because you are always programming to support some other goal, and the more you know about that goal the better you'll perform (I've encountered some European graduate programs that require the study of computing in combination with some other specialty, and you build your thesis by solving a domain-specific problem in that other specialty).
I also think that knowing more than just programming vastly improves your problem-solving skills (just as knowing more than one programming language vastly improves your programming skills). On multiple occasions I have encountered people, trained only in computer science, who seem to have more limits in their thinking than those who come from some other background, like math or physics, which requires more rigorous thinking and is less prone to "it works for me" solutions.
In one session a conference that I organized, one of the topics was to come up with a list of features for the ideal job candidate:
Take whatever risks you can -- the best risks are the scary ones, but in trying you will feel more alive than you can imagine. It's best if you don't plan for a particular outcome, because you will often miss the true possibilities if you're too attached to a result. My best adventures have been ones that have started with "lets do a little experiment and see where it takes us.
Some people will be disappointed by this answer, and reply "yes, that's all very interesting and useful. But really, what should I learn? C++ or Java?" I'll fend these off by repeating here: I know it seems like all the ones and zeroes should make everything deterministic, so that such questions should have a simple answer, but they don't. It's not about making one choice and being done with it. It's about continuous learning and sometimes, bold choices. Trust me, your life will be more exciting this way.
Here's an earlier piece I wrote on how I got started in programming. I found all these to be interesting and stimulating takes on the same subject:
In a future article (I'll post the link here when it's done), I will talk about the importance of understanding management and business issues, whether or not you ever plan to be a manager, and in that article I'll include a list of books that (even though they're about management) you should read to prepare yourself for your career.
Have an opinion? Readers have already posted 24 comments about this weblog entry. Why not add yours?
If you'd like to be notified whenever Bruce Eckel adds a new entry to his weblog, subscribe to his RSS feed.
中文:
Bruce Eckel:编程生涯
作者 Bruce Eckel 是编程界的大牛,著有大名鼎鼎的《Thinking in C++》和《Thinking in Java》。 本文是他对程序员(尤其是新手)的忠告。
================华丽的分割线================
大家总是问一个错误的问题:“我应该学习C++还是Java?”在本文中,我将告诉大伙儿:对于选择编程生涯真正需要关注的是哪些问题。
请 注意,这篇文章的目标读者并不是那些已经做出自己选择的人。(对于这些人而言)你会继续自己的编程生涯,而不管别人会怎么说。因为它已经渗透到你的血液 中,你已经无法摆脱。你已经知道答案:C++、Java、Shell脚本、Python、还有其它一大堆的语言和技术,你都理所当然地会去学习。甚至有可 能你才仅仅14岁,就已经知道好几种不同的语言。
问我这样的问题的人可能来自其他行业,或者来自诸如Web开发之类的领域。他们知道HTML是一种类编程语言,而且想尝试构建某些更大型的应用。但我特别希望,当你在问这个问题时,你已经意识到了想要在计算机领域取得成功,你需要掌握自学能力,而且永不停息。
在这个领域做得越多,我越觉得软件开发比任何行业都更接近于写作。 我们从来不知道是什么造就了优秀的作者,我们只知道什么时候我们会喜欢某个人的文字。编程不是一种工程,仅需要把东西从入口倒进去,然后再转动手柄。把软 件开发看成确定性的,是一个诱人的想法。因为这个想法,人们总想搞出一些工具来帮我们开发出想要的软件。但是我的经验告诉我,事实并非如此——人的重要性 远高于流程。而软件是否运行在一部精确的机器上已经越来越不重要了——这犹如测不准原理对人类的影响。
我的父亲是造房子的,小时候我偶尔会帮忙打下手,放放砖块之类。他和他的木工告诉我,他们是为我好才让我干这些活——这样我就不至于走入这个行业。事实确实是这样。
我 们不妨把软件开发比作盖房子。造房子的人当然不可能完全一样。这些人里面有:混凝土工、屋顶工、管道工、电工、砖瓦工、水泥工、瓦片工、搬运工、粗木工、 细木工。当然,还有工头。每个工种都需要相应的技能,这些技能都需要花时间和精力去掌握。跟软件开发一样,造房子也是一个“建立/推翻”的过程。如果你想 很快地获得回报,你可能从搬运工和砖瓦工开始做,这样的话,你无需太多的学习曲线就可以获得回报。当需求很多时,你的工作会很稳固,甚至收入也可能提升 ——如果没有足够的人手的话。但是,一旦行情不妙,木匠甚至工头就可能把砖瓦工一脚踢开。
当互联网刚刚兴起时,仅仅是花一点时间学习HTML,你就可以得到一份薪水丰厚的工作。但是当形势惨淡时,对于技能的要求更高了——HTML程序员(就像搬运工和砖瓦工一样)第一个被抛弃了,而拥有更高技能的程序员则留了下来。
我想说的是: 除非你准备活到老学到老,不然的话,不要进入这个行业!编程看起来似乎是一个高收入而又稳定的工作。但要做到这一点,唯一的途径是:始终让自己更有价值。
当然,你总能找到例外。总有那么一些人,仅仅学了一门编程语言,就可以胜任留在一个岗位上,而不需要增长他的技能。但他们只是幸免于难而已,他们最终无疑是很脆弱的。为了不让自己变得脆弱,你需要持续的提高自己,通过阅读、加入用户组、参加研讨会…… 你学得越深入,你就越有价值,也就意味着你有更好的职业前景,可以配得上更高的薪水。
另 一个方法是:先大致地了解这个领域,找到最适合你的地方。打个比方:我的兄弟对软件很感兴趣,也进入了这个行业,但他的工作是安装、维修、升级电脑。他总 是一丝不苟,所以当他把电脑搞好,一定会很完美——不只只是软件,连电线都会被仔细地捆好。他总是生意兴隆,远远超出他的精力所能及。他甚至都不用担心 .com 泡沫的崩溃。显然他的饭碗不容易被抢走。
我在高校里待了很久,甚至还在UCLA(加州大学洛杉矶分校)开始进修博士学位,后来 又幸运地终止了。我说“幸运”是因为我不再喜欢呆在学校,而我之前在高校待了那么久,只是因为我很享受它。但我所享受的,基本上是不务正业的东西——艺术 和舞蹈课,在校报工作,还有一小撮计算机课程(之所以说计算机课程“不务正业”,是因为我本科是物理专业,研究生才是计算机专业)。虽然我在学术上远谈不 上卓越(有意思的是很多当时也许不会接受我这个学生的学校现在却用我的书做教材)。我真的很享受作为学生的日子,当我完成博士课程,也许会以一个教授的身 份终老一生。
但就如现在看到的,我在学校里最大的收获恰恰来自我那些“不务正业”的课程,它们拓展了我的思维,使之超越了“我们已经知道 的东西”。在计算机领域中,你总是为某种目标而编程。你对目标了解得越多,你就做得越好。我遇到过一些欧洲的研究生,他们需要结合其它专业领域来搞编程, 他们的论文需要解决这个专业领域的特定的问题。
了解编程之外的领域,将会极大得提高你解决问题的能力 (就如同多学几种编程语言将极大地提高你的编程技能)。很多时候,我发现仅仅学习计算机专业的学生,比那些(除了计算机之外)拥有其它背景的学生,在思维上有更多的局限性。因为后者有着更严谨的思维,也不那么容易想当然。
有一次我组织了一次会议,其中一个议题是:理想的应聘者有哪些特征: ◇把学习当成生活方式。比如:你应该知道不止一种语言,没有什么比学习一门新语言更能让你开阔眼界了。 ◇知道如何获取知识 ◇Study prior art ◇善用工具 ◇学会把事情简化 ◇理解业务 ◇为自己的错误负责。“我就是这样的”是不能接受的托词。能找到自己的失误。 ◇成为一个领导者,善于沟通和激励。 ◇搞清楚你在为谁服务 ◇没有绝对正确的答案(更好的方法总是存在的)。展示并讨论你的代码,不要带着感情因素——你的代码并不等于你本人。 ◇明白完美是渐进的
要 尝试一些冒险的事情——尤其是那些令人害怕的冒险。当你尝试之后,将体会到出乎意料的兴奋。(在冒险的过程中)最好不要刻意去计划某个特定的结果。当你过 于注重结果,你往往会错过那些真正有价值的问题。我的冒险往往是这样开始的——“我们先做些试验,看看它会把我们带到什么地方”。
或许某 些人会对我的回答感到失望,并回复我说:“是的,这很有趣也很有用。但我到底应该学什么?C++还是Java?” 我再重复一次:并不是所有的问题都有一个唯一的简单的答案。问题的关键不在于选择某个编程语言,然后掌握之。问题的关键在于:持续学习,并且很多时候,有 不止一个选择。相信我所说的,你的生活会更精彩!
洋文原始出处: http://www.artima.com/weblogs/viewpost.jsp?thread=259358 来源: [http://www.rootsir.com/transshipment/2012/709.html](http://www.rootsir.com/transshipment/2012/709.html)
]]>By 刘未鹏 – July 10, 2011
不知不觉《知其所以然》系列竟然也写到第三篇了,虽然前面两篇也说了不少,但是总觉得还有东西没有说“透”,或者说没有说“好”。所以这篇试图从不同的角度用更好的例子来继续深入阐述。(感谢silwile对本文的review和意见)
广大码农同学们大多都有个共识,认为算法是个硬骨头,很难啃,悲剧的是啃完了还未必有用——除了面试的时候。实际工程中一般都是用现成的模块,一般只需了解算法的目的和时空复杂度即可。
不过话说回来,面试的时候面算法,包括面项目中几乎不大可能用到的算法,其实并不能说是毫无道理的。算法往往是对学习和理解能力的一块试金石,难的都能掌握,往往容易的事情不在话下。志于高者得于中。反之则不成立。另一方面,虽说教科书算法大多数都是那些即便用到也是直接拿模块用的,但不幸的是,我们这群搬砖头的有时候还非得做些发明家的事情:要么是得把算法当白盒加以改进以满足手头的特定需求;要么干脆就是要发明轮子。所以,虽说面试的算法本身未必用得到,但熟悉各种算法的人通常更可能熟悉算法的思想,从而更可能具备这里说的两种能力。
那么,为什么说算法很难呢?这个问题只有两种可能的原因:
下面会说明,算法之所以被绝大多数人认为很难,以上两个原因兼具。 我们说算法难的时候,有两种情况:一种是学算法难。第二种是设计算法难。对于前者,大多数人(至少我当年如此)学习算法几乎是在背算法,就跟背菜谱似的(“Cookbook”是深受广大码农喜爱的一类书),然而算法和菜谱的区别在于,算法包含的细节复杂度是菜谱的无数倍,算法的问题描述千变万化,逻辑过程百转千回,往往看得人愁肠百结,而相较之下任何菜谱涉及到的基本元素也就那么些(所以程序员肯定都具有成为好厨师的潜力:D)注意,即便你看了算法的证明,某种程度上还是“背”(为什么这么说,后面会详述)。我自己遇到新算法基本是会看证明的,但是发现没多久还是会忘掉,这是死记硬背的标准症状。如果你也啃过算法书,我相信很大可能性你会有同感:为什么当时明明懂了,但没多久就忘掉了呢?为什么当时明明非常理解其证明,但没过多久想要自己去证明时却发现怎么都没法补上证明中缺失的一环呢?
初中学习几何证明的时候,你会不会傻到去背一个定理的证明?不会。你只会背结论。为什么?一方面,因为证明过程包含大量的细节。另一方面,证明的过程环环相扣,往往只需要注意其中关键的一两步,便能够自行推导出来。算法逻辑描述就好比定理,算法的证明的过程就好比定理的证明过程。但不幸的是,与数学里面大量简洁的基本结论不同,算法这个“结论”可不是那么好背的,许多时候,算法本身的逻辑就几乎包含了与其证明过程等同的信息量,甚至算法逻辑本身就是证明过程(随便翻开一本经典的算法书,看几个经典的教科书算法,你会发现算法逻辑和算法证明的联系有多紧密)。于是我们又回到刚才那个问题:你会去背数学证明么?既然没人会傻到去背整个证明,又为什么要生硬地去背算法呢?
那么,不背就不背,去理解算法的证明如何?理解了算法的证明过程,便更有可能记住算法的逻辑细节,理解记忆嘛。然而,仍然不幸的是,绝大多数算法书在这方面做的实在糟糕,证明倒是给全了,逻辑也倒是挺严谨的,可是似乎没有作者能真正还原算法发明者本身如何得到算法以及算法证明的思维过程,按理说,证明的过程应该反映了这个思维过程,但是在下文关于霍夫曼编码的例子中你会看到,其实饱受赞誉的CLRS和《Algorithms》不仅没能还原这个过程,反而掩盖了这个过程。
必须说明的是,没有哪位作者是故意这样做的,但任何人在讲解一个自己已经理解了的东西的时候,往往会无意识地对自己的讲解进行“线性化”,例如证明题,如果你回忆一下高中做平面几何证明题的经历,就会意识到,其实证明的过程是一个充满了试错,联想,反推,特例,修改问题条件,穷举等等一干“非线性”思维的,混乱不堪的过程,而并不像写在课本上那样——引理1,引理2,定理1,定理2,一口气直到最终结论。这样的证明过程也许容易理解,但绝对不容易记忆。过几天你就会忘记其中一个或几个引理,其中的一步或几步关键的手法,然后当你想要回过头来自己试着去证明的时候,就会发现卡在某个关键的地方,为什么会这样?因为证明当中并没有告诉你为什么作者当时会想到证明算法需要那么一个引理或手法,所以,虽说看完证明之后,对算法这个结论而言你是知其所以然了,但对于算法的证明过程你却还没知其所以然。在我们大脑的记忆系统当中,新的知识必须要和既有的知识建立联系,才容易被回忆起来(《如何有效地学习与记忆》),联系越多,越容易回忆,而一个天外飞仙似地引理,和我们既有的知识没有半毛钱联系,没娘的孩子没人疼,自然容易被遗忘。(为什么还原思维过程如此困难呢?我曾经在知其所以然(一)里详述)
正因为绝大多数算法书上悲剧的算法证明过程,很多人发现证明本身也不好记,于是宁可选择直接记结论。当年我在数学系,考试会考证明过程,但似乎计算机系的考试考算法证明过程就是荒谬的?作为“工程”性质的程序设计,似乎更注重使用和结果。但是如果是你需要在项目中自己设计一个算法呢?这种时候最起码需要做的就是证明算法的正确性吧。我们面试的时候往往都会遇到一些算法设计问题,我总是会让应聘者去证明算法的正确性,因为即便是一个“看上去”正确的算法,真正需要证明起来往往发现并不是那么容易。
所以说,绝大多数算法书在作为培养算法设计者的角度来说是失败的,比数学教育更失败。大多数人学完了初中平面几何都会做证明题(数学书不会要求你记住几何所有的定理),但很多人看完了一本算法书还是一团浆糊,不会证明一些起码的算法,我们背了一坨又一坨结论,非但这些结论许多根本用不上,就连用上的那些也不会证明。为什么会出现这样的差异?因为数学教育的理想目的是为了让你成为能够发现新定理的科学家,而码农系的算法教育的目的却更现实,是为了让你成为能够使用算法做事情的工程师。然而,事情真的如此简单么?如果真是这样的话干脆连算法结论都不要背了,只要知道算法做的是什么事情,时空复杂度各是多少即可。
如果说以上提到的算法难度(讲解和记忆的难度)属于Accidental Complexity的话,算法的另一个难处便是Essential Complexity了:算法设计。还是拿数学证明来类比(如果你看过《Introduction to Algorithms:A Creative Approach》就知道算法和数学证明是多么类似。),与单单只需证明相比,设计算法的难处在于,定理和证明都需要你去探索,尤其是前者——你需要去自行发现关键的那(几)个定理,跟证明已知结论相比(已经确定知道结论是正确的了,你只需要用逻辑来连接结论和条件),这件事情的复杂度往往又难上一个数量级。
一个有趣的事实是,算法的探索过程往往蕴含算法的证明过程,理想的算法书应该通过还原算法的探索过程,从而让读者不仅能够自行推导出证明过程,同时还能够具备探索新算法的能力。之所以这么说,皆因为我是个懒人,懒人总梦想学点东西能够实现以下两个目的:
想要做到这两点就必须尽量从知识树的“根节点”入手,虽然这是一个美梦,例如数学界寻找“根节点”的美梦由来已久(《跟波利亚学解题》的“一点历史”小节),但哥德尔一个证明就让美梦成了泡影(《永恒的金色对角线》));但是,这并不阻止我们去寻找更高层的节点——更具普适性的解题原则和方法。所以,理想的算法书或者算法讲解应该是从最具一般性的思维法则开始,顺理成章地推导出算法,这个过程应该尽量还原一个”普通人“思考的过程,而不是让人看了之后觉得”这怎么可能想到呢?
以本文上篇提到的霍夫曼编码为例,第一遍看霍夫曼编码的时候是在本科,只看了算法描述,觉得挺直观的,过了两年,忘了,因为不知道为什么要把两个节点的频率加在一起看做单个节点——一件事情不知道“为什么”就会记不牢,知道了“为什么”的话便给这件事情提供了必然性。不知道“为什么”这件事情便可此可彼,我们的大脑对于可此可彼的事情经常会弄混,它更容易记住有理有据的事情(从信息论的角度来说,一件必然的事情概率为1,信息量为0,而一件可此可彼的事情信息量则是大于0的)。第二遍看是在工作之后,终于知道要看证明了,拿出著名的《Algorithms》来看,边看边点头,觉得讲得真好,一看就理解了为什么要那样来构造最优编码树。可是没多久,又给忘了!这次忘了倒不是忘了要把两个节点的频率加起来算一个,而是忘了为什么要这么做,因为当时没有弄清霍夫曼为什么能够想到为什么应该那样来构造最优编码树。结果只知其一不知其二。
必须说明的是,如果只关心算法的结论(即算法逻辑),那么理解算法的证明就够了,光背算法逻辑难记住,理解了证明会容易记忆得多。但如果也想不忘算法的证明,那么不仅要理解证明,还要理解证明背后的思维,也就是为什么背后的为什么。后者一般很难在书和资料上找到,唯有自己多加揣摩。为什么要费这个神?只要不会忘记结论不就结了吗?取决于你想做什么,如果你想真正弄清算法设计背后的思想,不去揣摩算法原作者是怎么想出来的是不行的。
回到霍夫曼编码问题,我们首先看一看《Algorithms》上是怎么讲的:
首先它给出了一棵编码树的cost function:
cost of tree = Σ freq(i) /* depth(i)
这个cost function很直白,就是把编码的定义复述了一遍。但是接下来就说了:
There is another way to write this cost function that is very helpful. Although we are only given frequencies for the leaves, we can define the frequency of any internal node to be the sum of the frequencies of its descendant leaves; this is, after all, the number of times the internal node is visited during encoding or decoding…
接着就按照这个思路把cost function转换了一下:
The cost of a tree is the sum of the frequencies of all leaves and internal nodes, except the root.
然后就开始得出算法逻辑了:
The first formulation of the cost function tells us that the two symbols with the smallest frequencies must be at the bottom of the optimal tree, as children of the lowest internal node (this internal node has two children since the tree is full). Otherwise, swapping these two symbols with whatever is lowest in the tree would improve the encoding.
This suggests that we start constructing the tree greedily: find the two symbols with the smallest frequencies, say i and j, and make them children of a new node, which then has frequency fi + fj. To keep the notation simple, let’s just assume these are f1 and f2. By the second formulation of the cost function, any tree in which f1 and f2 are sibling-leaves has cost f1 + f2 plus the cost for a tree with n – 1 leaves of frequencies (f1 + f2), f3, f4, .., fn. The latter problem is just a smaller version of the one we started with.
读到这里我想大多数人有两种反应:
因为我当时也是这么觉得的。可是后来当我发现自己无法从头证明一遍的时候,我知道肯定是理解的不够深刻。如果理解的够深刻,那么基本上是不会忘掉的。
如果看完霍夫曼编码这样一个简短证明你觉得顺理成章,一切都挺显然,那就坏了,即便是看上去最基本的性质也往往实际上没那么显然。“逢山开路,遇水架桥”在我们今天看来是无比显然的事实,但是试想在没有桥的远古时代,一个原始人走到一条湍急的河流前,他会怎么想,他又能有什么法子呢?这是个他从来没有遇见过的问题。如果后来有一天,他路过另外一条小溪,看到小溪上有一截被闪电劈断的枯树,于是他踏着树干走过了小溪,并意识到“树横过河面”可以达到“过河”这个目的,这就将条件和目的建立了直接的联系(事实上,是自然界展示了这个联系,我们的原始人只是记住了这个联系)。后���他又路过那条河流,他寻思如何达到“过河”这个目的的时候,忽然意识到在他的记忆中已经遇到过需要达成同样目的的时候了,那个时候的条件是“树横过河面”,于是问题便归结为如何满足这个“树横过河面”的条件,而后一个问题就简单多了。(事实上波利亚在他的著作《How to Solve it》中举的正是这么个例子)
为什么那么多的算法书,就看不到有一本讲得好的?因为我们求解问题过程中的思维步骤太容易被自己当作“显然”的了,但除了我们天生就会的认知模式(联系,类比),没有什么是应该觉得显然的,试错是我们天生就会的思维法则么?是的,但是可供尝试的方案究竟又是怎么来的呢?就拿上面的例子来说,一个从没有见过枯树干架在小溪上的原始人,怎么知道用树架桥是一种可选的方案呢?俗话说巧妇难为无米之炊啊。我们大脑的神经系统会的是将目的和条件联系起来,第一次原始人遇到小溪过不去,大脑中留下了一个未实现的目的,后来见到小溪上的树干,忽然意识到树干是实现这个目的的条件,两者便联系起来了,因此问题就规约为如何架树干了。
回到《Algorithms》中的证明上,这个看似简洁明了的证明其实有几处非常不显然的地方,甚至不严谨的地方,这些地方也正是你过段时间之后试图自己证明的话会发现卡住的地方:
为什么要提到上面这几点不显然和不严谨的地方,因为只要当你看到算法书上出现不显然和不严谨的地方,基本上就意味着作者其实跳过了关键的思维步骤。
不幸的是《Algorithms》这本书里面讲霍夫曼编码已经算是讲的好的了,如果你翻开著名的CLRS,看一看当中是怎么证明的,你就知道我说的什么意思了。有时候这些证明是如此的企图追求formal和严谨,一上来就定义符号一大摞,让人看了就想吐。
说了这么多,有没有可能把霍夫曼编码讲的更好呢?前面说过,霍夫曼编码我记了又忘,忘了又记,好几次了,有一次终于烦了,心想如果要自己去证明,会怎么去证,那个时候我已经忘了《Algorithms》里面怎么讲的了。所以我得从头来起,首先,对于算法问题,有一个一般性原则是,先看一看解空间的构成。尤其是对于搜索问题(最优化问题可以看做搜索问题的一个特例),这一点尤其重要。霍夫曼编码的可能的编码树是有穷的,如果穷举所有的编码树,然后找到那棵代价最小的,这种方法至少是可行的,有了可行的方法(即便是穷举)至少让我们内心感到踏实。
接下来便是提高搜寻效率的问题。而提高搜寻效率的关键(同样也是一个一般性原则),便是尽量去寻找问题条件能够推导出来的性质,**然后利用这些性质去避免不必要的搜寻**,只要你学过二分搜索就应该理解这个一般性原则:二分搜索的效率之所以高于“穷搜”(O(n)),便是因为它利用了问题中的性质(有序)来避免了不必要的搜寻。有时候这个性质甚至可以直接将时间降为O(1),例如在一个有序数组中寻找出现次数大于n/2的数(假设该数存在),利用“该数一定出现在数组正中间”这个性质,我们直接就避免了所有的计算。
不过,话虽如此,有时候这些性质并不是那么“显然”的,需要对问题进行深入的折腾才能有可能发现。第三个一般原则:如果你要搜寻的元素是某个满足特定条件的元素(例如寻找最优解的时候,“最优”的定义就是这个“特定条件”),那么可以“倒过来推”(数学证明常用手法,结论当条件使),即假设你已经找到了你要找的元素,那么能得出哪些结论,每一个结论都是最优解的一个必要条件,而每一个必要条件都能够帮助你避免不必要的搜寻,因为你只要发现某个候选解不满足某个必要条件,就可以立即将其丢弃,前面提到的寻找出现次数大于n/2的例子是一个极端情况,我们得出的必要条件导致我们可以直接丢弃除中点元素之外的一切其他元素,再例如如果有人叫你寻找有序数组中最小元素,你会毫不犹豫地把该数组头尾元素中较小的那个给他,因为你知道“如果那个最小元素存在,那么它必然位于头尾”——这个必要条件直接允许你丢弃掉n-2个候选解。
回到霍夫曼编码问题,按照这个原则,我们会去假设已经得到了最优编码树,那么我们能够发现关于它的什么性质呢?这里又要提到另一个适用于很多最优化问题的原则(前面提到的原则适用于一般性搜索问题),所谓最优解,就是说比其他所有解都要更好,虽然这句话听上去像是废话,但是它的一个直接推论——比与它邻近的所有候选解都要好——就是一个非常有用的,不是废话的性质了。学过微积分的都知道,光滑函数的最值点必然是大(小)于其邻域内的所有点的,然后再根据这个就自然推出该点的一阶导数(切线斜率)必然为0的性质,这个性质(必要条件)让我们直接省掉了去整个区间内搜索的麻烦,从而可以直接锁定有限几个候选解。那么,既然我们说最优霍夫曼树一定比它“附近”的树更好,我们就想看看,怎么来找到它附近的树。我们知道要从一个点到它附近,往往是对这个点进行一些调整,例如N+1是到达附近的另一个整数。霍夫曼树是一棵树,所以对这棵树的所有的一次“改动”(或“折腾”)都能够到达与它的“改动”距离为1的点(是不是想起“编辑距离”这个概念),怎么改动呢?最符合直觉的(虽然并不是唯一的)改动便是把叶子节点进行互换。
于是我们得到一个重要的推论:
这个性质看上去有点像废话,值得费这么多事么?值得。因为虽然前文说了很多,但都是大多数人大脑里面既有的,一般性的法则,前面说过,如果我们能够从我们已经掌握的一般法则出发来推导出问题的解,那么记忆负担是最小的,因为这里面用到的所有法则我们都很清楚,也知道怎么一步步往下走。
上面这个性质究竟意味着什么呢?如果你假设这两个叶子节点的频率为f1和f2,深度为d1和d2,互换它们的时候,其他叶子节点的cost保持不变,令为常量C,那么互换前总cost为C+f1d1+f2d2,互换后为C+f1d2+f2d1,既然互换之后的树一定更”差“那么就是说f1d1+f2d2 < f1d2 + f2d1,简单变换一下就得到结论:f1(d1-d2)
有了这个结论之后,我们便能够对最优霍夫曼树的构建走出确定性的一步,即,将频率最低的两个叶子节点放在最底层。别小看这一步,这一步已经排除了大量的可能性。这里,我们容易一开始天真地觉得最底层只有这两个叶子节点,于是它们拥有共同父节点,这样一来霍夫曼树的整个拼图便已经拼好了一个小小的角落。
然后我们会发现,要是它们不是兄弟怎么办呢?这里提到另一个一般原则——归约。不是兄弟的情况能否归约为是兄弟的情况?反正我们要求的是一个最优解,而不是所有的最优解,我们只需证明,如果当这两个最低频率的叶子不是兄弟的时候的确存在着某棵最优霍夫曼树,那么通过交换它们各自的兄弟,从而让这两个叶子团聚之后,修改后的树仍然是最优的就可以了。事实情况也的确如此,证明非常直接——既然这里涉及到的所有4个节点都在最底层同一个高度上,那么互相交换的时候不会改变他们任何一个人的深度值,所以总cost不会改变。
但是接下来我们犯了难,整个树的一个小小的樱桃状的局部是确定下来了,接下来怎么办呢?一个最自然的思路就是考虑第三小的叶子,因为前面说了,元素频率越低就越位于树的底部嘛。第三小的叶子有两种可能的归属,一是跟最小的两个叶子同样位于最底层(这不会违反我们前面得到的推论),这个时候第三小的叶子的兄弟叶子肯定是第四小的叶子,如下图:
另一种归属就是往上一层去(注意,一旦第三小的叶子往上去了一层,那么剩下的所有叶子都必须至少在这个层以上),往上一层去了之后,它的兄弟是谁呢?不妨将它和刚才第一第二叶子的父节点结为兄弟(前面证明过,同层之前节点互换不会改变编码的cost),如下图:
可是现在问题出现了:虽然第一步构建(最小的两个叶子)是确定的,但是到了第二步摆在我们面前的就有两个选择了,到底选择哪个呢?一个办法就是把两种选择都记下来,然后继续往下走。可是别小看两种选择,接下去每一步都有两种选择的话就变成指数复杂度了。所以现在我们便有了动机回头看一看,看问题中是否有什么没有发现的性质能够帮助我们再排除掉其中一个选择。理想情况下如果每一步都是必然的,确定的,那么N步我们就可以构建出整棵树,这是我们希望看到的,抱着这个良好的愿望,我们仔细观察上面两种构型,一个自然而然的问题是:这两种构型都有潜质成为最优解吗?如果我们能够证明其中一种构型不能成为最优解那该多好?就省事多了嘛。这里引入另一个一般性的解题法则:特例。我们的大脑喜欢具体的东西,在特例中折腾和观察会方便的多。
上面这个{1, 2, 3, 4}的例子就是个很好的特例,如图(注:图中节点旁的数字一概为频率值,而非编号):
多加折腾一番也许我们不难发现,如果将1,2及其父节点跟叶子4进行交换(注意:交换的时候1,2也被一同带走了,因为反正1,2两个节点已确定是好兄弟永远不会分家了,折腾的时候只能作为一个整体移动,所以这里也可以说是交换子树),那么树的编码将会变得更优,因为这样一次交换会将1和2的深度+1,意味着整棵树的代价+3,而同时会将叶子4的深度-1,也就是说整棵树的代价-4,总体上整棵树的代价就是+3-4=-1(注意,在计算的时候我们只需考虑被交换的局部,因为树的其他部分的代价保持不变)。如下图:
这个交换启发了我们,其实前面一开始说的交换两个叶子节点可以推广为交换内部节点和叶子节点,然后很快我们就会意识到其实可以推广到交换任意两个节点。(注意,当我们说交换内部节点的时候,其实是连同该内部节点作为局部根节点的整个子树都交换过去)于是前面我们的推论就可以推广为:
这个推论很容易理解,只不过是多增加了一种“编辑”最优霍夫曼树的方法罢了(记住最优霍夫曼树无论怎么“编辑”都不会变得更“好”,包括“交换子树”这种“编辑”),我们前面没有想到这种“编辑”方法是因为它不那么显然,而且当时我们已经想到一种最直接的“编辑”方法了,即交换叶子,就容易顺着那个思路一直走下去,直到我们发现必须寻找新的性质,才回过头来看看有没有其他法子。
当然,并不排除一开始就想到这种推广的可能性,问题求解的过程并不是这么线性的,如果我们习惯了推而广之的思维,也许一下就能想到这个推广来。类似的,也不排除从另一种思路出发想到这种推广的可能性。所以这里只是可能的思维轨迹中的一种,重��在于其中并没有某处忽然出现一个不知从哪里冒出来的,神启一般的结论。
刚才提到,构造最优树的第二步是考虑第三小的叶子,但也有另一种常见的思维:考虑到第一步(即选取频率最小的两个叶子)所做的事情是从N个叶子中选择两个黏在一起作为兄弟,那么也许对于一些人来说自然而然的第二步就是试图继续选取两个节点黏在一起作为兄弟(注意这里不仅可以选择叶子,也可以选择已经生成的内部节点),然后依次类推来拼完整棵树。按照这一思路,第二步的选项仍然还是集中在第三小的叶子上,因为这个选择要么是让第三第四小的叶子结拜为兄弟,要么是让最小两个叶子的父节点和第三小的叶子结拜。
回到刚才我们的推论:在最优霍夫曼树中,无论互换哪两个节点,得到的树都变得更“差”(交换内部节点则是连同该内部节点作为局部根的子树一同带走) 。根据这个推论我们容易计算出,在最优霍夫曼树当中,两个内部节点n1和n2,如果n1比n2更深,那么n1下面的所有叶子的频率之和必然要小于n2下面所有叶子的频率之和。如果交换的是一个内部节点和一个叶子节点,则道理是类似的。这个性质的证明和上面的类似,就不赘述了。
这个性质暗示了一个重要的推广结论:如果我们把每个内部节点的所有叶子的频率之和标在它旁边,那么整棵树的每个节点便都有了一个数值,这个数值遵循统一的规律:即越往深层越小。这就意味着,我们刚才的二选一困境有办法了!当我们将最小的两个叶子f1和f2合并的时候,生成了一个新的节点M,这个节点有一个数字(为两个叶子的频率之和f1+f2),根据上面的推论,这个数字f1+f2跟所有频率一同,遵循最小的在最底层的原则,所以我们下一步必须在剩下的那些互相之间关系待确定的节点(叶子节点和内部节点)之中,即{(f1 + f2), f3, f4}里面选择最小的两个数字结合成兄弟(由于f1和f2这两个节点已经铁板钉钉结为整体了,所以从集合里面可以看做移除)。到这里,我们就发现递归已经出现了,接下去的过程对于绝大多数人应该就真的很显然了。
以上的解释,比《Algorithms》更简短吗?显然不是。反而要长得多(其实真正的思维过程比这要更长,因为中间还会涉及各种不成功的尝试)。但是它比《Algorithms》当中的版本更不容易被忘记,因为其中关键的思维拐点并不是毫无来由的,而是从你已经熟知的,或者说虽然不知道,但容易理解的一般性解题法则出发自然推导出来的,所以你基本上不需要记忆什么东西,因为你需要记的已经在你脑海中了。
在上面的证明过程中,还有一个不像看上去那么显然的事情:在我们寻找最优霍夫曼树的时候,我们曾经试图去比较假想的最优树和它的“临近”的树,从而去探索最优树的性质。但是,究竟什么是临近的树?在前面的讲解中,我们说如果交换A和B这两个叶子节点,便得到一颗不同的树,可以看做和原树的“编辑距离”为1的树。但是,真的这么显然么?难道除了交换叶子的位置,就没有其他办法去“折腾”这棵树了?后来我们看到,可以交换子树而不仅仅是叶子,而交换子树让我们得到了至关重要的推论。此外,如果不是交换,而是像AVL树那样“旋转”呢?说到底,二叉树是一个离散的东西,并不像连续值那样,天生就有“距离”这个概念,如果我们离散而孤立地去看待所有的树,那么没有什么临近不临近的,临近本是一个距离的概念,除非我们定义树和树之间的距离函数,才能说临近与否,而距离函数怎么定义才是“显然”的呢?
还有,其实以上只是试图给出最优霍夫曼树的证明的一个更自然的过程,而当年霍夫曼面临这个问题的时候根本还没有人想到要用二叉树呢!更不要说在二叉树的前提之下进行证明了。根据wikipedia的介绍,霍夫曼同学(当年还在读Ph.D,所以的确是“同学”,而这个问题是坑爹的导师Robert M. Fano给他们作为大作业的,Fano自己和Shannon合作给出了一个suboptimal的编码方案,为得不到optimal的方案而寝食难安,情急之下便死马当活马医扔给他的学生们了)当年为这个问题憔悴了一个学期,最后就快到deadline的时候“忽然”想到二叉树这个等价模型,然后在这个模型下三下五除二就搞定了一篇流芳千古的论文,超越了其导师。
最后说两个有趣的现象:也许很多人会觉得,越是大师来写入门教科书越是好,其实很多时候并非如此,尤其是在算法设计和数学领域,往往越是在其中浸淫久了越是难写出贴近初学者的书,因为大量对初学者来说一点都不显然的事情在他看来已经是“不假思索”了,成了他的内隐记忆,尤其是当他想要和你解释一个复杂的东西的时候你就会发现他会常常逻辑跳跃,满嘴跑术语,根本没有意识到别人对有些术语和隐含的逻辑根本没有像他那样的理解。
最适合将一个东西讲给别人听的时候并不是等懂了很多年以后,而是刚刚弄懂的时候,这个时候从不懂到懂的差别记忆还非常鲜明,能够清清楚楚地记得到底是哪些关键的地方是最折磨人的,也最能够站在不懂者的角度来思考问题。像波利亚这样,成了大师还能够站在不懂者角度去换位思考的,可以说是凤毛麟角。所以说前Amazon CAO(首席算法官)的《Introduction to Algorithms: a Creative Approach》绝对是本罕见的好算法书)
知其所以然(一)里面曾经提到,要弄清来龙去脉,最好去看看原始作者是怎么想的,可是正如上文所说,即便是最初的发明者,在讲述的时候也会有意无意地“线性化”,我就去查看了霍夫曼最初的论文,那叫一个费解,不信你可以自己看看(PDF)。
可以归约为搜索算法的问题(非常多)一般来说相对还是有一些头绪的,因为搜索空间一般还比较容易界定,难点在于要从问题的条件中推导出用于节省搜索的性质。而策略设计问题则完全是另一个世界,因为策略的设计空间貌似是可列无穷的,常常让人感觉无从下手,摸不着头绪,许多让人挠头的智力问题就有这个特点(例如著名的100个囚徒和1个灯泡的房间就让很多人有这种感觉),策略设计问题也有一些较通用的法则,以后再说。
怎么才能在学算法的时候学到背后的东西呢?有以下几点很重要:
最后留个问题:虽然按照上文的方式来构造霍夫曼树一定能够得到一个最优树,但是怎么证明一定能得到呢?乍一看这个问题似乎很多余,因为证明很简单:我们拼装整棵树的每一步都没得选,而且每一步都必然拼凑出最优树的一个小小局部,如果最终还没有得到最优树的话,只能说最优树是不存在的了,然而最优树是一定存在的,因为所有树的集合是有穷的,有穷集必有最值,因此证毕。这个证明固然是没问题的,但它其实是一个间接证明,换句话说,我们在构建树的过程中的逻辑是这样的:“之所以我们选择粘结n1和n2,是因为其他粘法必然违反最优树的两个性质。所以我们别无选择。”但是,这并没有说,我们选择了粘结n1和n2,一定就符合了最优树的性质。(也就是说“其他做法都是错”并不能推出“这种做法必然对”,这就像是你在一大堆豆子当中寻找一个特殊的豆子,你拿起一个,看看不是,扔掉,又拿起一个,还不是,扔掉,排除到最后只剩一个豆子了,假设你又知道这个特殊的豆子必然存在,那么这个时候你根本不用看就知道这个豆子一定就是你要找的)那么,你能否直接证明,拼装最优树的过程每一步都符合最优树的性质呢?
P.S.
[1] 《逃出你的肖申克》和《BetterExplained》是我喜欢的两个系列,还会继续写,我有很多问题,也在Evernote里面记了不少零碎的思考和资料,但只有当我觉得理解的足够深入,系统,以及手头有足够的有意思和有说服力的例子的时候,我才会把整条线串起来成文,所以这事慢慢来不着急,反正这个博客也不会关掉。
[2] 工作之后可用业余时间急剧减少,已经陆续基本把GReader砍掉了,时间再往前推,砍掉邮件列表,再往前是Twitter,再往前是BBS。现在基本就只剩邮件了。越来越发现当时间有限的时候,看书比看网要有效得多,也不会那么信息焦虑,网络上的那些消息当中真正重要的会自己来找你,不用每天去刷屏。不过有个例外,我过一阵子就会去逛一下Amazon的个性化推荐项目。如果你已经工作,苦于时间有限,我建议你这么做。最近看过的几本值得好好推荐的书有:《Number Sense》,《Reading in the Brain》,《The Vision Revolution》,《The Tell-Tale Brain》,《Kluge》。
[3] 顺便吐槽国内出版社引进Pop Science类书籍的效率和质量,就我观察,台湾引进Pop Science类书籍需要延迟两年左右,大陆则从三四年到无限期不等(某种程度上,一个国家的出版方的认识水平,决定了这个国家大众的认识水平。你去看下我在豆瓣的书单就知道有多少好书与国内读者失之交臂了),例如《Number Sense》这本好书,到现在还没有引进,99年出版的书啊。《Kluge》更是译为《乱乱脑》这种坑爹的书名,封面搞得跟少儿读物一样。《Reading in the Brain》引入的算较快的,但也延迟了一年半了,而且翻译质量也不是很上乘(算是不功不过吧),说到这里要赞中信出版社,最近一年引入了很多给力的Pop Science畅销书,眼光还算不错。最近在Amazon上搜一些好的发展心理学的书,通过Amazon的推荐引擎看到了《Pink Brain,Blue Brain》,这本受到因研究大脑记忆的分子机制而获诺奖的Eric Kandel盛赞的科普09年就出了,到现在国内影子都见不着,还好在卓越上买到了原版。虽然基本还没开始看,但可以郑重推荐给初为父母的同学们:) Tags: 算法
来源 :http://mindhacks.cn/2011/07/10/the-importance-of-knowing-why-part3/
]]>By 刘未鹏 – July 10, 2011
不知不觉《知其所以然》系列竟然也写到第三篇了,虽然前面两篇也说了不少,但是总觉得还有东西没有说“透”,或者说没有说“好”。所以这篇试图从不同的角度用更好的例子来继续深入阐述。(感谢silwile对本文的review和意见)
广大码农同学们大多都有个共识,认为算法是个硬骨头,很难啃,悲剧的是啃完了还未必有用——除了面试的时候。实际工程中一般都是用现成的模块,一般只需了解算法的目的和时空复杂度即可。
不过话说回来,面试的时候面算法,包括面项目中几乎不大可能用到的算法,其实并不能说是毫无道理的。算法往往是对学习和理解能力的一块试金石,难的都能掌握,往往容易的事情不在话下。志于高者得于中。反之则不成立。另一方面,虽说教科书算法大多数都是那些即便用到也是直接拿模块用的,但不幸的是,我们这群搬砖头的有时候还非得做些发明家的事情:要么是得把算法当白盒加以改进以满足手头的特定需求;要么干脆就是要发明轮子。所以,虽说面试的算法本身未必用得到,但熟悉各种算法的人通常更可能熟悉算法的思想,从而更可能具备这里说的两种能力。
那么,为什么说算法很难呢?这个问题只有两种可能的原因:
下面会说明,算法之所以被绝大多数人认为很难,以上两个原因兼具。 ]]>
2013年7月31日 陈皓
我对数据挖掘和机器学习是新手,从去年7月份在Amazon才开始接触,而且还是因为工作需要被动接触的,以前都没有接触过,做的是需求预测机器学习相关的。后来,到了淘宝后,自己凭兴趣主动地做了几个月的和用户地址相关数据挖掘上的工作,有一些浅薄的心得。下面这篇文章主要是我做为一个新人仅从事数据方面技术不到10个月的一些心得,也许对你有用,也许很傻,不管怎么样,欢迎指教和讨论。
另外,注明一下,这篇文章的标题模仿了一个美剧《权力的游戏:冰与火之歌》。在数据的世界里,我们看到了很多很牛,很强大也很有趣的案例。但是,数据就像一个王座一样,像征着一种权力和征服,但登上去的路途一样令人胆颤。
在Amazon里从事机器学习的工作时,我注意到了Amazon玩数据的三种角色。
Data Analyzer:数据分析员。这类人的人主要是分析数据的,从数据中找到一些规则,并且为了数据模型的找不同场景的Training Data。另外,这些人也是把一些脏数据洗干净的的人。
Research Scientist:研究科学家。这种角色主要是根据不同的需求来建立数据模型的。他们把自己戏称为不近人间烟火的奇异性物种,就像《生活大爆炸》里的 那个Sheldon一样。这些人基本上玩的是数据上的科学
Software Developer :软件开发工程师。主要是把 Scientist 建立的数据模型给实现出来,交给Data Analyzer去玩。这些人通常更懂的各种机器学习的算法。
我相信其它公司的做数据挖掘或是机器学习的也就这三种工作,或者说这三种人,对于我来说,
最有技术含量的是 Scientist,因为数据建模和抽取最有意义的向量,以及选取不同的方法都是这类人来决定的。这类人,我觉得在国内是找不到的。
最苦逼,也最累,但也最重要的是Data Analyzer,他们的活也是这三个角色中最最最重要的(注意:我用了三个最)。因为,无论你的模型你的算法再怎么牛,在一堆烂数据上也只能干出一堆垃圾的活来。正所谓:Garbage In, Garbage Out !但是这个活是最脏最累的活,也是让人最容易退缩的活。
最没技术含量的是Software Developer。现在国内很多玩数据的都以为算法最重要,并且,很多技术人员都在研究机器学习的算法。错了,最重要的是上面两个人,一个是苦逼地洗数据的Data Analyzer,另一个是真正懂得数据建模的Scientist!而像什么K-Means,K Nearest Neighbor,或是别的什么贝叶斯、回归、决策树、随机森林等这些玩法,都很成熟了,而且又不是人工智能,说白了,这些算法在机器学习和数据挖掘中,就像Quick Sort之类的算法在软件设计中基本没什么技术含量。
目前所流行的Buzz Word——大数据是相当误导人的。在我眼中,数据不分大小,只分好坏。
在处理数据的过程中,我第一个感受最大的就是数据质量。下面我分几个案例来说明:
在Amazon里,所有的商品都有一个唯一的ID,叫ASIN——Amazon Single Identify Number,这个ID是用来标识商品的唯一性的(来自于条形码)。也就是说,无论是你把商品描述成什么样,只要ASIN一样,这就是完完全全一模一样的商品。
这样,就不像淘宝一样,当你搜索一个iPhone,你会出现一堆各种各样的iPhone,有的叫“超值iPhone”,有的叫“苹果iPhone”,有的叫“智能手机iPhone”,有的叫“iPhone 白色/黑色”……,这些同一个商品不同的描述是商家为了吸引用户。但是带来的问题有两点:
1)用户体验不好。以商品为中心的业务模型,对于消费者来说,体验明显好于以商家为中心的业务模型。
2)只要你不能正确读懂(识别)数据,你后面的什么算法,什么模型统统没用。
所以,只要你玩数据,你就会发现,如果数据的标准没有建立起来,干什么都没用。数据标准是数据质量的第一道关卡,没这个玩意,你就什么也别玩了。所谓数据的标准,为数据做唯一标识只是其中最最基础的一步,数据的标准还单单只是这个,更重要的是把数据的标准抽象成数学向量,没有数学向量,后面也无法挖掘。
所以,你会看到,洗数据的大量的工作就是在把杂乱无章的数据归并聚合,这就是在建立数据标准。这里面绝对少不了人肉的工作。无非就是:
聪明的人在数据产生之前就定义好标准,并在数据产生之时就在干数据清洗的工作。
一般的人是在数据产生并大量堆积之后,才来干这个事。
另外,说一下Amazon的ASIN,这个事从十多年前就开始了,我在Amazon的内网里看到的资料并没有说为什么搞了个这样一个ID,我倒觉得这并不是因为Amazon因为玩数据发现必需建议个商品ID,也许因为Amazon的业务模型就是设计成以“商品为中心”的。今天,这个ASIN依然有很多很多的问题,ASIN一样不能完全保证商品就是一样的,ASIN不一样也不代表商品不一样,不过90%以上的商品是保证的。Amazon有专门的团队Category Team,里面有很多业务人员天天都在拼命地在对ASIN的数据进行更正。
用户地址是我从事过数据分析的另一个事情。我还记得当时看到那数以亿计的用户地址的数据的那种兴奋。但是随后我就兴奋不起来了。因为地址是用户自己填写的,这里面有很多的坑,都不是很容易做的。
第一个是假/错地址,因为有的商家作弊或是用户做测试。所以地址是错的,
比如,直接就输入“该地址不存在”,“13243234asdfasdi”之类的。这类的地址是可以被我的程序识别出来的。
还有很能被我的程序所识别出来的。比如:“宇宙路地球小区”之类的。但这类地址可以被人识别出来。
还有连人都识别不出来的,比如:“北京市东四环中路23号南航大厦5楼540室”,这个地址根本不存在。
第二个是真地址,但是因为用户写的不标准,所以很难处理,比如:
缩写:“建国门外大街” 和 “建外大街”,“中国工商银行”和“工行”……
错别字:“潮阳门”,“通慧河”……
颠倒:“东四环中路朝阳公园” 和 “朝阳公园 (靠东四环)” ……
别名:有的人写的是开发商的小区名“东恒国际”,有的则是写行政的地名“八里庄东里”……
这样的例子多得不能再多了。可见数据如果不准确,会增加你处理的难度。有个比喻非常好,玩数据的就像是在挖金矿一样,如果含金量高,那么,挖掘的难度就小,也就容易出效果,如果含金量低,那么挖掘的难度就大,效果就差。
上面,我给了两个案例,旨在说明——
1)数据没有大小之分,只有含金量大的数据和垃圾量大的数据之分。
2)数据清洗是一件多么重要的工作,这也是一件人肉工作量很大的工作。
**所以,这个工作最好是在数据产生的时候就一点一滴的完成。
有一个观点:如果数据准确度在60%的时候,你干出来的事,一定会被用户骂!如果数据准确度在80%左右,那么用户会说,还不错!只有数据准确度到了90%的时候,用户才会觉得真牛B。但是从数据准确度从80%到90%要付出的成本要比60% 到 80%的付出大得多得多。大多数据的数据挖掘团队都会止步于70%这个地方。因为,再往后,这就是一件相当累的活。
我不知道有多少数据挖掘团队真正意识到了业务场景和数据挖掘的重要关系?我们需要知道,根本不可能做出能够满足所有业务的数据挖掘和分析模型。
推荐音乐视频,和电子商务中的推荐商品的场景完全不一样。电商中,只要你买了一个东西没有退货,那么,有很大的概率我可以相信你是喜欢这个东西的,然后,对于音乐和视频,你完全不能通过用户听了这首歌或是看了这个视频就武断地觉得用户是喜欢这首歌和这个视频的,所以,我们可以看到,推荐算法在不同的业务场景下的实现难度也完全不一样。
说到推荐算法,你是不是和我一样,有时候会对推荐有一种感觉——推荐就是一种按不同维度的排序的算法。我个人以为,就提一下推荐这个东西在某些业务场景下是比较Tricky的,比如,推荐有两种(不是按用户关系和按物品关系这两种),
一种是共性化推荐,结果就是推荐了流行的东西,这也许是好 的,但这也许会是用户已知的东西,比如,到了北京,我想找个饭馆,你总是给我推荐烤鸭,我想去个地方,你总是给我推荐天安门故宫天坛(因为大多数人来北京就是吃烤鸭,就是去天安门的),这些我不都知道了嘛,还要你来推荐?另外,共性化的东西通常是可以被水军刷的。
另一种是一种是个性化推荐,这个需要分析用户的个体喜好,好的就是总是给我我喜欢的,不好的就是也许我的口味会随我的年龄和环境所改变,而且,总是推荐符合用户口味的,不能帮用户发掘新鲜点。比如,我喜欢吃辣的,你总是给我推荐川菜和湘菜,时间长了我也会觉得烦的。
推荐有时并不是民主投票,而是专业用户或资深玩家的建议;推荐有时并不是推荐流行的,而是推荐新鲜而我不知道的。你可以看到,不同的业务场景,不同的产品形态下的玩法可能完全不一样,
另外,就算是对于同一个电子商务来说,书、手机 和服装的业务形态完全不一样。我之前在Amazon做Demand Forecasting(用户需求预测)——通过历史数据来预测用户未来的需求。
对于书、手机、家电这些东西,在Amazon里叫Hard Line的产品,你可以认为是“标品”(但也不一定),预测是比较准的,甚至可以预测到相关的产品属性的需求。
但是地于服装这样的叫Soft Line的产品,Amazon干了十多年都没有办法预测得很好,因为这类东西受到的干扰因素太多了,比如:用户的对颜色款式的喜好,穿上去合不合身,爱人朋友喜不喜欢…… 这类的东西太容易变了,买得人多了反而会卖不好,所以根本没法预测好,更别Stock/Vender Manager 提出来的“预测某品牌的某种颜色的衣服或鞋子”。
对于需求的预测,我发现,长期在这个行业中打拼的人的预测是最准的,什么机器学习都是浮云。机器学习只有在你要面对的是成千上万种不同商品和品类的时候才会有意义。
数据挖掘不是人工智能,而且差得还太远。不要觉得数据挖掘什么事都能干,找到一个合适的业务场景和产品形态,比什么都重要。
我看到很多的玩大数据的,基本上干的是数据统计的事,从多个不同的维度来统计数据的表现。最简单最常见的统计就是像网站统计这样的事。比如:PV是多少,UV是多少,来路是哪里,浏览器、操作系统、地理、搜索引擎的分布,等等,等等。
唠叨一句,千万不要以为,你一天有十几个T的日志就是数据了,也不要以为你会用Hadoop/MapReduce分析一下日志,这就是数据挖掘了,说得难听一点,你在做的只不过是一个统计的工作。那几个T的Raw Data,基本上来说没什么意义,只能叫日志,连数据都算不上,只有你统计出来的这些数据才是有点意义的,才能叫数据。
当一个用户在面对着自己网店的数据的时候,比如:每千人有5个人下单,有65%的访客是男的,18-24岁的人群有30%,等等。甚至你给出了,你打败了40%同类型商家的这样的数据。作为一个商户,面对这些数据时,大多数人的表现是完全不知道自己能干什么?是把网站改得更男性一点,还是让年轻人更喜欢一点?完全不知道所措。
只要你去看一看,你会发现,好些好些的数据分析出来的结果,看上去似乎不错,但是其实完全不知道下一步该干什么?
所以,我觉得,数据分析的结果并不仅仅只是把数据呈现出来,而更应该关注的是通过这些数据后面可以干什么?如果看了数据分析的结果后并不知道可以干什么,那么这个数据分析是失败的。
综上所述,下面是我觉得数据挖掘或机器学习最重要的东西:
1)数据的质量。分为数据的标准和数据的准确。数据中的杂音要尽量地排除掉。为了数据的质量,大量人肉的工作少不了。
2)数据的业务场景。我们不可能做所有场景下的来,所以,业务场景和产品形态很重要,我个人感觉业务场景越窄越好。
3)数据的分析结果,要让人能看得懂,知道接下来要干什么,而不是为了数据而数据。
搞数据挖掘的人很多,但成功的案例却不多(相比起大量的尝试来说),就目前而言,我似乎觉得目前的数据挖掘的技术是一种过渡技术,还在摸索阶段。另外,好些数据挖掘的团队搞得业务不业务,技术不技术的,为其中的技术人员感到惋惜……
不好意思,我只给出了问题,没有建议,这也说明数据分析中有很多的机会……
最后,还要提的一个是“数据中的个人隐私问题”,这似乎就像那些有悖伦理的黑魔法一样,你要成功就得把自己变得黑暗。是的,数据就像一个王座一样,像征着一种权力和征服,但登上去的路途一样令人胆颤。
(全文完)
]]>2013年7月31日 陈皓
我对数据挖掘和机器学习是新手,从去年7月份在Amazon才开始接触,而且还是因为工作需要被动接触的,以前都没有接触过,做的是需求预测机器学习相关的。后来,到了淘宝后,自己凭兴趣主动地做了几个月的和用户地址相关数据挖掘上的工作,有一些浅薄的心得。下面这篇文章主要是我做为一个新人仅从事数据方面技术不到10个月的一些心得,也许对你有用,也许很傻,不管怎么样,欢迎指教和讨论。
另外,注明一下,这篇文章的标题模仿了一个美剧《权力的游戏:冰与火之歌》。在数据的世界里,我们看到了很多很牛,很强大也很有趣的案例。但是,数据就像一个王座一样,像征着一种权力和征服,但登上去的路途一样令人胆颤。
在Amazon里从事机器学习的工作时,我注意到了Amazon玩数据的三种角色。
Data Analyzer:数据分析员。这类人的人主要是分析数据的,从数据中找到一些规则,并且为了数据模型的找不同场景的Training Data。另外,这些人也是把一些脏数据洗干净的的人。
Research Scientist:研究科学家。这种角色主要是根据不同的需求来建立数据模型的。他们把自己戏称为不近人间烟火的奇异性物种,就像《生活大爆炸》里的 那个Sheldon一样。这些人基本上玩的是数据上的科学
Software Developer :软件开发工程师。主要是把 Scientist 建立的数据模型给实现出来,交给Data Analyzer去玩。这些人通常更懂的各种机器学习的算法。
我相信其它公司的做数据挖掘或是机器学习的也就这三种工作,或者说这三种人,对于我来说,
最有技术含量的是 Scientist,因为数据建模和抽取最有意义的向量,以及选取不同的方法都是这类人来决定的。这类人,我觉得在国内是找不到的。
最苦逼,也最累,但也最重要的是Data Analyzer,他们的活也是这三个角色中最最最重要的(注意:我用了三个最)。因为,无论你的模型你的算法再怎么牛,在一堆烂数据上也只能干出一堆垃圾的活来。正所谓:Garbage In, Garbage Out !但是这个活是最脏最累的活,也是让人最容易退缩的活。
最没技术含量的是Software Developer。现在国内很多玩数据的都以为算法最重要,并且,很多技术人员都在研究机器学习的算法。错了,最重要的是上面两个人,一个是苦逼地洗数据的Data Analyzer,另一个是真正懂得数据建模的Scientist!而像什么K-Means,K Nearest Neighbor,或是别的什么贝叶斯、回归、决策树、随机森林等这些玩法,都很成熟了,而且又不是人工智能,说白了,这些算法在机器学习和数据挖掘中,就像Quick Sort之类的算法在软件设计中基本没什么技术含量。 ]]>
近期看见一篇来自Intel的很有意思的分析文章,作者提到在他向45名与会的各公司程序员/开发经理/战略师提问“什么是实施并行编程的最大障 碍”时,下面五个因素被提及的次数最多:遗留代码(legacy code)、教育(education)、工具(tools)、对众核趋势的恐惧 (fear of many cores)以及可维护性(maintainability)。文章虽然是一篇Intel Parallel Studio的软文,但是其中提及的这五大障碍却非常值得讨论,下面是我对这五大障碍的一些粗浅看法,希望能起到一个抛砖引玉的作用,欢迎大家给出你们 的看法。
( 注:好像Google Group让我原文的一些超链接都失效了,如果想有更好的阅读体验,请看 http://www.parallellabs.com/2010/03/22/five-obstacles-that-slow-down-parallelism/ )
遗留代码 众所周知,并行化实施最大的困难在于怎样把公司的那些遗留代码给并行化。100K~1000K的代码量都非常正常,而并行编程本身又是非常容易出错的, 一大堆诸如data race, dependency, non-deterministic, memory consistency, dead lock, serialization bottleneck, thread safe等的问题随便哪一个拉出来都让人头大,更别说要高 效可靠的并行化这些庞大的遗留代码了。更困难的是很多遗留代码还有编写者已经离职,文档注释不全等问题,这无疑是雪上加霜。从成本上来讲,如果能通过一 些优秀的编译器(例如Intel的ICC)自动并行化一些遗留代码无疑是最省钱的,但是这种方法最大的缺陷就在于像Intel ICC这种自动型编译器 能自动并行化的代码非常少,从而导致它能提供的性能优化非常有限,而且就算是真正能获得speedup的代码也有很多约束条件(例如loop的循环之间 没有dependence,并且该loop应该是一个程序热点)。所以目前的现状就是大量的遗留代码并不能有效的被并行化,从商业的角度上来讲,如果能 有一种解决方案能在短时间内快速可靠的通过实施并行化让遗留代码获得10%~30%的性能提升,那么它就已经能为公司节省大量成本了。
教育 第二大的障碍可能就是程序员缺乏并行编程方面的教育了。其实并行编程已经有二三十年的历史了,不过在多核CPU出现之前那些并行编程都是“专家”们的玩 具。那时候的并行编程大都是跑在集群、大型机或者服务器上,通过MPI(message passing model)或者SMP(对称多处理器,即一 个主板上有多个单核CPU,属于shared memory model)来完成并行计算。Pthread标准是1995年建立的,之后出来了 Windows版的Win32 thread,后来又出来了“编译指导”、面向data parallel模型的OpenMP(OpenMP 3.0加 入了task parallel支持),task parallel的鼻祖Click,Intel的Intel Thread Building Block(task parallel),Java 1.5开始对多线程提供较好的支持(加入了Java Memory Model),近几年随着 GPU的发展,Nvidia又开始搞CUDA(data-parallel),Apple一看不对,并行编程以后是主流啊,我得插一手,于是自己撑旗弄 了个针对CPU和GPU混合编程的OpenCL,微软一看也坐不住了也要随着Visual Studio2010开始搞C/#的并行库,马上C++0x也 要加入多线程支持,甚至连老古董Erlang也因为天生支持并行被重新热炒,总之随着摩尔定律在串行世界的失效,整个业界都开始被迫往并行编程方向发 展。
可是对程序员来说呢是什么情况呢?我们现在所接受的教育大都还是串行世界的那些算法和数据结构,高德纳在一篇访谈里说“在我看来,这种现象或多或少是由 于硬件设计者已经无计可施了导致的,他们将Moore定律失效的责任推脱给软件开发者,而他们给我们的机器只是在某些指标上运行得更快了而已。如果多线 程的想法被证明是失败的,我一点都不会感到惊讶……你听说过有多少程序员对这种未来一片光明的机器抱有强烈的兴趣?我几乎没有听说过,除了他们的诉苦。 尽管我们学院那些搞硬件的家伙一直想让我相信我是错的”,可见硬件发展被迫向多核转移直接导致程序员们免费的午餐已经结束了。那么程序员现在受到良好的 并行编程教育了吗?很显然,现在随便问一个普通的程序员:“你觉得并行编程容易么?”,十有八九会说“我觉得很难”。前一阵有人讨论服务器编程用多线程 好还是多进程好?其实根本原因就在于哪怕多线程有性能优势,可是isolation的多进程模式能在programming productivity 和performance之间找到比较好的折衷,所以国内很有服务器开发者都选择了多进程(例如云风)。从大趋势上来讲,不管是研究体系机构的,还是写 OS/Compiler的,还是定义编程语言的,现在都在积极努力的为广大的程序员提供一个更容易使用的并行编程模型,Intel这几年不也在搞多核培 训么,这都是好现象,但是,离真正的全民并行编程时代还有相当长的路要走。近几年的IT技术热门书单里面很少有并行编程的书籍就是个很好的写照。
(1) IDE: Intel Parallel Studio,微软马上出来的VS2010算一个,Sun的Sun Studio(不知道它的未来如 何,但是它本来就很小众),Nvidia的CUDA平台什么的就先不算了 (2) Compiler: Intel的ICC(能自动并行化一些代码),Nema Labs的FASThread(针对遗留代码的解决方案,能快速 可靠的指导程序员实施并行化) (3) Performance Tuning: Intel Vtune Analyzer(综合性能分析),Thread profiler, Acumem的Thread Spotter(针对多核Cache的性能分析和优化) (4) Debugging: Petra的Jinx
总体上我个人觉得它们对程序员来说确实有用,但是前提条件是你要会用。这其实又跟第二点“教育”有很大关系了。
对众核的恐惧 现在我们看到4核已经非常普遍了,等过几年那可就是8核,16核,32核了。怎样确保你的代码在核数倍增的趋势下仍能有很好的性能,很好的可伸缩性?这 真的是个问题。我现在所做的研究就是多线程程序中锁竞争的性能分析,目的就是为了帮助程序员更好的解决由锁竞争造成的性能瓶颈。实际上,为了得到很好的 可伸缩性,程序员需要往往需要使用并行友好的数据结构(例如concurrent hash map),使用细粒度的锁甚至无锁编程,设计data parallel的算法,性能调优(例如典型的false sharing问题)等等等等,这其中每一项都是不小的挑战。我曾经翻译过的一篇文章对设计 多线程程序提供了一些有用的建议。
可维护性 毫无疑问,我们希望并行代码能够与现存的runtime系统、build系统以及其他现有代码一起正确的工作,我们更希望这些并行代码易于理解、便于维 护并且有较长的生命周期。可是现阶段真正掌握并行编程的程序员少之又少,而且并行编程又是这么困难,哪怕你对这些并行代码只是做一些小小的改动都很有可 能导致新的bug,新的性能瓶颈,那真的是一件非常痛苦的事情。 显示删减掉的内容
机械唯物主义 : linjunhalida
]]>近期看见一篇来自Intel的很有意思的分析文章,作者提到在他向45名与会的各公司程序员/开发经理/战略师提问“什么是实施并行编程的最大障 碍”时,下面五个因素被提及的次数最多:遗留代码(legacy code)、教育(education)、工具(tools)、对众核趋势的恐惧 (fear of many cores)以及可维护性(maintainability)。文章虽然是一篇Intel Parallel Studio的软文,但是其中提及的这五大障碍却非常值得讨论,下面是我对这五大障碍的一些粗浅看法,希望能起到一个抛砖引玉的作用,欢迎大家给出你们 的看法。
( 注:好像Google Group让我原文的一些超链接都失效了,如果想有更好的阅读体验,请看 http://www.parallellabs.com/2010/03/22/five-obstacles-that-slow-down-parallelism/ )
]]>
一篇好文。直指中国教育的病根。文章提到的一些想法自己也思考过,只是没有文中说的这么透彻。很多东西只是自己一些模糊的想法,看到文章豁然开朗。总结一下,文章说了几个东西:
文章有点长,大家需要耐心看看,呵呵。过去的二十多年我们无法选择,但是将来的几十年我们可以做我们自己的选择,如何选择呢?问问自己的心 。很多同学、朋友都在找工作,呵呵,谨以此文共勉,祝大家都能找到那片属于自己的天地!
http://club.chinaren.com/105403342.html
98年本科毕业,又顺利地被保研,当时的我只是一个憨憨的书呆子,纯洁的如同高中生,在清华这种和尚庙一般的理工学校里呆了四年,女孩似乎是山下的老虎,神秘得让我一见就脸红心跳。未来是什么对于我就是“读完研再说”,反正成绩还行,不读白不读。天上掉了馅饼,用我的兄弟的话来说。香港正好回归一周年,教育部要选派一批本科毕业生去香港科技大学读研,以加强两地的教育和科研交流。清华当然要占不少名额,系里的几个牛人去了美国,所以这个饼就掉到了我头上,确实是个不错的饼,不用考G、考托、全额奖学金,连什么手续都是学校和教育部包办了,我分文不花,后来香港科大的联络人抱怨中国的办事效率和程序烦琐,至于怎样的麻烦过程,我至今都一无所知。
香港科大
就这么糊里糊涂地来到了香港。依山傍海的科技大学美得如同世外桃源,现代感的建筑更让我们爽眼。当时的一个哥们说:“妈的,就是用银子在荒山野岭堆出来的,这样的物质条件算是让我满足了。”后来得知就是亚洲最美丽校园,倒也丝毫不怀疑。据说是香港政府感到了贸易和服务的优势正受中国沿海城市的挑战,而科技就是竞争力,就下了狠心投钱建了这学校,请来了学者。耗资400亿港币,相当于微软公司一年的纯利。组织的参观,教授的讲话,英语的培训很快就过去了,当时的新奇兴奋也褪得干净,每天面对这青山海景,最后也麻木得没有感觉了。由此可以推测娶一个漂亮老婆是没有多大意义的,如果不是为了炫耀。教授大多是华人,台湾和大陆出身的不少,反倒香港人是少数派,很多都是在北美的名校里拿了PhD,奔这里的高薪来了,他们的PhD头衔总要和名字相片挂一起,挂一辈子,Harvard和Standford之类的当然就香了。正教授可以一年拿到一百多万港币,也就是一个月可以买小汽车,比一般的美国大学高。知识真的值钱了,让我们充满了对未来的向往。有回和教授们吃饭,谈及大陆大学教授的待遇,他们就感慨:“知识分子真被廉价到了可耻的地步。”我们也无话可说,反正不是我的错。然而钱不是好拿的,很多教师正是三十出头,教授职称还未到手,和学校只是几年合同,其他的学者也不断在申请进来,所以压力颇大,辛勤程度比公司打工仔有过之而无不及。既然自己做学问要紧,培养学生的事就要往后排了。刚近来时很多教师和我们亲切讲话,之后就不见了,好久不见就不认得。研究生当然有导师的,只要自己不去找他,他是肯定不会找我的。上课之后就是绝对的自由,当时自由得很是惬意。
萧伯纳说人生的苦闷有二,一是欲望没有被满足,二是它得到了满足。这话的确是部分的真理。当我住在这绝世美丽的地方,可以随心所欲的去商店买东西不用担心付不起帐,可以任意的支配自己时间时,最初的半年里,却发现情绪每况愈下。西方化的建筑设计将个人的所谓 privacy保护发挥到极致,进了宿舍就基本感觉不到他人的存在,同单元的人也有独立的卧室,大家都是进了房,将门一关,隔离了,谁也不好意思去敲门。刚来时认识的一伙人,后来发现根本遇不着,如同消失了一般。同住一起的是三十好几的叔叔级人物,偶尔可以说上一两句话,却永无可能说很多。大家都像是住在不同的空间里做研究,忙碌的无瑕顾及他人。
平心而论,对于一个成熟的研究者,如果他有确定的目标和兴趣,对生活人生都不再有不切实际的幻想,准备投身科学研究中,那么这里真是一个好环境。但是我种茫茫睁着无知的眼睛的毛头小子,却是完全另外的感觉。那种茫然的苦闷感觉真是难以描述,找不到人玩,只是将窗户开了又关,关了又开,不停的喝水,仍然感觉不舒服。怀念在清华的破楼里相互串门打闹的日子,怀念抱着篮球在走廊里叫一声就应者云集的日子,可是怀念解决不了问题。以孩子的心理去进入成熟严谨的环境,不可不说是一次考验。
多年的功利教育的辛勤培养,我一路顺当地走过来,发现完全的上当。我在成功的通过了一次次考后,最终都不知道我为什么要通过这些占距人生的考试,这个所谓的优秀学生只是在不停地让自己去符合那个“优秀”的外在标准来麻痹自己的虚荣心,而自己,那个真正的自己却一直没有存在过,没有发育过。我学的任何课程都无法帮我解决当时的苦恼,那么每天学那些微分方程又是为了什么?还去为了父母的微笑,人们的赞许吗?年年得奖学金的清华毕业生是了这么一个怪物:不知道自己要什么,也不知道生活是什么,对社会毫无接触,二十出头,可是见女孩子就一身不自在,会解各式各样的方程,却不能解决自己的困惑,硕士博士的路就在眼前,可是不知道还应不应该这样走下去,这状态难道就是我的追求?一个智商还不错的人努力多年就变成这样?这是一个问题,很早就有了,只不过太晚地暴露出来,我相信这样的问题依然将被很多师弟师妹们面临,我相信在清华依旧有很多像我当年一样的学生。当看到他们天真的讨论: G 2///, 托 6//,GPA 3./, 学校名次Top //, 仿佛几年的辛劳就只为那么点数字,人生的终极标就是 go abroad. 我无法不为他们忧虑。这也是促使我写这篇文章的主要原因。
很多人没有对做研究的真正兴趣,但是用尽了精力去获得一个去国外做科学研究的机会,就洋溢在掩饰不住的喜悦里,甚至对人生毫无真正规划,对自己的兴趣一无所知,为出国而出国,那将在告别父老乡亲后去迎接苦闷的开端。香港的学生很实际,决大多数本科毕业就去赚钱,三十之间为结婚买房奋斗,如果告诉一个香港人说你二十八了还在读博士,他会觉得你很失败,可能是根本不会赚钱。而留下来读博士的香港学生,就是真的很喜欢作研究的人,扎实地做事,他们的认真让我们一批朝三暮四,心猿意马的大陆学生汗颜。
生活在香港
都说香港是弹丸之地,其实一千多平方公里的面积也不算小,不过大多是山,可利用的地方不多,很多商业区都是添海造出来的。亚热带的气候,又在到处是山和海湾的地方,风景当然好。香港的气候比北京舒适一万倍,冬天冷不了,夏天也不太热,甚至没有明显的四季感。只是上半年天气有些潮。成天都有湿湿的感觉,北方人有点受不了。香港的交通极其发达,公共车从不拥挤,也很少堵车,可是香港的道路比北京的窄得多,车也不会少,布局和管理更好而已,看来北京走向国际化还须努力。这里是名符其实的购物天堂,东西也不算贵,电器和服装可能比北京便宜,特别是国际名牌,由于没有关税,肯定要比大陆便宜。所以不必带很多衣服来,足够便宜了。但是服务业,比如吃饭,理发,涉及到员工劳动和地租的就要比大陆贵好几倍。可以随便往来深圳也是在香港的一大好处,一天可以轻松来回好几次,在香港读书的学生可一得到香港的临时身份证,加上护照上盖个章,就可以自由出入境了。
常有人问及香港的影视明星,可是到了香港就觉得那些人也只是打工仔,背后是更有影响力的老板,一旦老板不想捧了,明星就会很快消失,新人会取而代之。看到他们卖力地载歌载舞,其实也是生存需要,在商业社会里那是绝对的驱动力。香港的金融和资讯服务相当发达,在所谓第一世界里也算相当突出,可以很便宜的享受到信用卡,电讯,互联网服务,因此有些人在香港呆久了再回来反而不适应了,主要就是这些方面,当然还有其他制度等软件原因。 说到学校的生活,物质条件比国内任何大学好,甚至条件好过美国不少学校,香港的学生很少住宿学校,所以一到周末放假学校就很冷清。通常大陆学生独享学校设备,偌大电脑房和运动场,舒服的游泳池,都有不少美好回忆。学生宿舍条件不错,可以作饭,自己作比在餐厅里吃来的便宜,所以大陆学生会乐此不疲,周末常三五成群,作吃的为乐。餐厅里中西餐都有,中餐以广东口味为主,忙起来时以营养为重,口味不对也只能将就吃了。
现在在香港的大陆学生不算多,总共有四五百人,各个学校都有学生联谊会,是比较松散的组织,也有一些机会认识朋友。周末会组织放放电影,搞舞会。临近考试或论文时,谁也没心思搞活动。香港的学生很好打交道,在成熟的社会里长大的人,心理相对简单且好玩,不像一些大陆学生常常过分盘算自己的明天,将自己逼的很累。他们对大陆也渐渐感兴趣,虽然他们常常不知道湖南和四川,只说得上秦始皇和xx。只要主动点和他们交流,是可以结识不少朋友的,粤语不是障碍,很多人可以听普通话,而且,广东话不难学,不留神就长进不少。
关于工作机会
很多人就终于跳到北美去了,大多还是接着读书,从这个意义上讲,香港只是跳板。在香港留下工作的机会不多,如果在进香港的第一天了解这一点,是有好处的。也有回祖国的,我就是,所以我在这里写文章了,看到很多朋友询问去香港读书的问题,作为过来人,就写了这些,如果能给这些朋友提供一点有益的信息,就很满足了。
上次写了文章发表在海外学子版,很多朋友给我回信,给了我很大的鼓励,真的没想到过自己的东西会给别人带来影响。留学的经历给了我很多,几乎是一个脱胎换骨的过程,在一篇文章里是不可能都讲完的,所以我再写一个续集,好莱坞搞续集纯是为赚钱,我呢是什么都不图,万一有 ppmm看了之后找我,最爽不过。将心底里的一点点“龌龊” 都暴露出来,可以痛快讲了。
凡事都是虚空
来自发展中国家的人,难免在神情上都多一丝生存紧张,中国在海外的留学生尤其让人感觉到这一点。看不到出自内心的笑,连谈话时也似乎只有一个主题:今后有什么打算?每做一件事,都在问自己:对我有没有好处? 坦白的说我自己刚到香港时就是这样,只觉得自己多么没着落,无根无底的飘在他乡,我要努力啊,绝不可浪费自己的任何精力,房子,车子,名誉,地位,还有漂亮老婆,我什么都要啊。要学最能给我带来利益的东西,去做最有利自己的事情,直到我成功。
当时我就是这么典型功利,到现在我都想这样痛骂自己。
数学指出函数的极大值往往在最不稳定的点取到,人追求极端就会失去内心的平衡,到时候就不难体会到数学原理的深刻。我很快让我的功利心理逼到无路可走了,对所学的东西怀疑,担心自己变成书呆子,对自己有信心,找不到真正的朋友,找不到让身心平静的乐趣,每天都在心潮起伏。最后我去找学生辅导员。愚蠢的诉说倒不多提了,不过我记得他大胡子的脸有了微笑,眼睛里放出宽容而温和的光。他告诉我觉的我很有意思,他第一次遇到这么坦白的学生。“那些东西有什么意义呢,你怀疑得很好。“之后就翻出圣经来,给我读某些章。
Everything is meaningless.竟是圣经里的话语。那是我看到的最为震惊的一句话,也是我后来觉得最深刻的一句话。中国人很难理解,对在功利教育里熏陶过来,缺少人格教育的中国学生,更无异于晴天霹雳。成绩,offer, 学位,这样那样的好处,每天拼命算计的东西有什么意义?假设你突然死掉,世界将会怎样?世界将一样绚丽,地球转的一样快,太阳系每天在宇宙中换一个位置。大海还是大海,波涛还是波涛,一样的花开花落,潮起潮落。你的亲人可能会掉眼泪,但是周围的人在三个月内将你忘个干净,那是你曾经那么在乎他们怎么看你的一群人啊。如果上帝存在,在他的眼里,你是多么可怜的小虫子,在活着的短暂岁月里,在最美好的青春里,都不曾快乐过,用尽心力去聚集一大堆外在和心灵没有关系的小东西,只是出于对未来的没有信心,小小的心灵在接近熄灭的一天还在发出那个愚蠢的声音,让你忙碌,让你忧虑的声音:我要,我还要。天底下充满了这样的小虫子,当一个离开了,又有一个来了,做着同样的事情,汹涌着同样的小小念头,受着同样的煎熬。于是上帝要感慨了:虚空的虚空,凡事都是虚空。已有的事,后必再有;已行的事,后必再行。日光之下,并无新事。
已过的时世代,无人纪念;将来的世代,后来的人也不纪念。 ------圣经 旧约 传道书
我不是在传教,当时的辅导员也不是在传教,但是让我立刻看到自身的渺小,物质追求的虚妄,内心的愚昧。看看资本主义的学生辅导,是不是比我们这边高明多了?马哲曾帮助过我们什么?
不要忧虑“不要为明天忧虑,天上的飞鸟,不耕种也不收获,上天尚且要养活它,田野里的百合花,从不忧虑它能不能开花,是不是可以开得和其它一样美,但是它就自然的开花了,开得比所罗门皇冠上的珍珠还美。你呢,忧虑什么呢?人比飞鸟和百合花贵重多了,上帝会弃你不顾吗?”
一个朋友告诉我,他在等美国offer 的时候,常常梦到接到牛校offer, 过度兴奋到醒,更为郁郁,感慨 “但愿长醉不复醒”。这样的故事大家听了不会太惊诧,由此不难理解《儒林外史》中的进中举了。而得到offer的人到了海外,往往要经历更多的梦醒时分。
为什么活得这么累?生命本是如此美丽,连飞鸟和野花都可以尽情地享受上天的恩赐,而这些有高等思维的聪明人,却活活让思维搞得神情郁郁,哀声叹气。
常有人感叹西方人笑起来那么真实,那么出自内心,探讨起来,又归结到他们更有钱,他们的社会更发达。可我觉得那不是原因。原因就是他们比中国学生更接近飞鸟和野花罢了,更接近《阿甘正传》里的弱智罢了。他们更天真,相信那个万能的上帝会永不遗弃他,所以他们可以少想很多的问题,反而过得更顺利,在团队里表现得更凝聚,因为过分的私心是无法向大家共同的上帝交代的,他们可以很快做出一个Microsoft,一个Dell,但是大家可以看看中国的北大方正,联想,新浪,管理层一年的地震比台湾还多, 这么多年来,连冲出亚洲的野心都没有真正实现过。这难道不是上帝给西方人带来的好处,耶稣说信我就可以得救,不管这个上帝是不是虚拟的,但他在事实上填补了人性的巨大空白,人家的Microsoft 就证明了他的存在,正如计算机的虚拟内存,尽管虚拟,但事实上的作用是巨大的。中国学生总是怀疑这个看不见的上帝是否存在,更在私下里说,他对我能带来好处吗?其实中国人什么都不信,只信好处,从古时的考八股起,读书就是为了好处。因此,大家每天活在害怕没有好处的忧郁里,想靠自己小小的思维,在着巨大的世界系统里去谋取好处,上帝忍了泪水,背过脸去。思维的无奈我并不主张虚无,尽管我在上一篇文章里尽力去指出物质追求的虚妄。
正如萨特认为,人生本是本无意义,但是怎样摆脱虚无却是有意义的。王朔的意义在于砸碎那些没有意义的假崇高,伍迪.艾伦的意义就在于不断指出人生的荒谬。如果一切都是那么可笑,我们怎样面对每天的24小时?但是活着就是这么简单,它只是一个过程,简单而自然地发生,以至于任何干扰和关注都是多余。就像飞鸟掠过天空,野花静静地开放。能把什么东西叫做现在吗?你能占有什么东西吗?一切的意义只在时间的流动的河中。就像一团火,哪个燃烧的过程才叫火,一旦过程停止了,火不存在了。人的思维在作怪,它是一个双面的东西,它不总是带给我们好处,虽然我们对它有那么多自信。思维在很多时候严重地干扰了那个自然的生命过程,它在想单个的状态好不好,值不值得,合不合规范,能给自己带来什么,所以我们很快变得不快乐,不安稳,再也无法享受那种自然的喜悦了,正像被摄像的人,他的表情立刻不自然起来。恐怖片里的鬼魂可能一直不曾出现,人们却开始牙齿打颤,是被自己思维折磨而已。学计算机的朋友肯定知道操作系统将一个进程悬挂起来的意思。人的那个蠢笨不堪的思维,凭什么要常驻内存?它那么长期的运转,又真正解决了多少问题?为什么不在必要的时候悬挂它,去享受生命的自然?明白这一点将改变你的生活,思维会使你陷入矛盾,很多时候它是多余的,用心去体会,甚至用毛孔去感受就足够了。当你不再判断,不再分辨,不再比较,不再权衡,你就立刻、和谐起来。“采菊东篱下,悠然见南山”。那时,还用考虑什么呢?“此间有真意,欲辩已忘言”,连言语都是多余,因为言语来自思维。佛陀的捻花一笑,详和的神情,虽静坐,似乎已飞跃世间一切,他坐在了那个生命的根本之上, 再也没有一丝的不和谐。
读书的时候,我常常到海边听滔声,坐下来看着太阳落下,那会是我一天最美好的时间,当太阳没下去,晚霞渐渐褪去颜色,波浪依然轻轻拍打岸边,幕色从四周将我围过来,静默中我会在心灵里升起喜悦,感觉到冥冥中那个永恒的力量,它在紧紧将我抱住,天地万物和我一样同在,也被温和地抱着,我将永不孤独,永不伤心,永不绝望,因为那力量就一直在那里,将永远在那里,我是它的恩赐,我的灵魂从未像那时一样枝繁叶茂,内心从未像那时一样宁静和谐。我不用去分辨那种力量,是上帝也好,上天也好,老子说的道也好,有什么关系呢?分辨只是是思维常干的蠢事罢了。所有的心灵都是一样的,所以我相信所有人都有那个和谐的状态,就像收音机有那个频道一样,只不过太多人没有调到过。太阳,大海,清风明月,鸟语花香,生生不息的物种,是多么大的恩赐啊,只在我们断暂的生命里才可以感受到,可是太多的人从不念及。他们将自己全部地交给了少得可怜的脑细胞,心灵交给了那个拙劣的 CPU, 时时刻刻在做狭窄不堪的运算和判断,所以才会长时间挣扎焦虑,只看到85分和90分的区别, 5000元月薪和10万年薪的不同,牛校和烂校的分辨。所以“郁闷”,“无耻”,“倒霉”,“不爽”,“急”,这样的词汇就开始在嘴边泛滥了,就像破电脑的出错提示一样多。
本没有打算再写很多了,关于人生的刨根问底本来就是沉重的课题,无异让学业繁多的学子们再怀疑自己,平添忧虑。倒不如多说点逗乐的事,每天多嘻嘻哈哈一阵。前不久见到北大的一个女生,说我前面介绍香港的文字很实用,后面的文章就越来越看不懂了,可以理解,并不是所有的人都要像我一样想这些问题的,特别是女孩,一天多说几声“挺好的”“好温馨哟”就算过得不错了,古今中外都不曾出过一个女哲学家。但是,这位未曾谋面的北大师弟在等我的续集,谢谢你, xmdl(阿扁鱼), 我不愿让你失望这一篇是为你而写的。
我们看的人文书前面提到的女生就问我,在留学过程中最大的收获是什么,我回答是长了见识。就像在小地方呆久的人出来见了大海,这个收获大得很。所以我渐渐地学会了真正的谦虚态度,越来越承认自己所可以理解到的,可以认识到的只是这世界的太小一部分。在我的脑力范围外有太大的空间,从这一点来看,我们每个人都对自己有过多的自负,每天都在或多或少的干着作井观天的蠢事,争论着盲人摸象的争论。
清华北大的学生的人文素养,我想,很多来源于图书馆的人文书籍,因为喜欢读书的学生多半在那里搬书回来看。可是那些书多产于七十,八十年代,基本上是被一把姓马的刀阉割了的太监式的书,我不怕得罪人。怎么阉割法?举个例子,“总体而言,宗教是唯 心的,错误的世界观,被统治 阶 级利用来麻痹被统治 阶级的广大人民...”从此,你知道了这一点,你么读释迦,读耶稣,读老庄,都觉得如同太监一般阴阳怪气。在红色的年代里,马刀所向无敌,包括孔夫子到孙中山,从曾国 藩到蒋介 石,都少有可以逃脱的,因为他们有“阶 级局限性”。
但是我到了香港,就看到了很多台湾的书,很多香港的书,原来这些书本不象太监的,甚至不比姓马的书少阳刚之气,可以读得让人忘食,哎,可怜它们的被阉。这些都是我以前脑子以外的东西,所以我立刻知道要谦虚了,人总是受着他的经历和环境的巨大局限,他甚至不意思到,没有选择地被限制隔离着。
耶稣呢,用我们的眼光看,他太失败了,没有妻子,没有儿子,没有房子,没有财产,没有地位,最后还要被钉死,他只是游走于四方去救助受苦受难的人们,他有余的眼光总是看到了世界的外面,因为他也到过更高的维度里。 庄子至今看来还是活得最浪漫最洒脱的中国人,他是超脱的同义词,他也是高维空间的蚂蚁。
去读他们,去体会那种来自另外一个维度的智慧的震撼,尽管你可能无法改变无奈的现实,但是可以深刻地改变自己,尽管无法摆脱沉重的肉身,依旧无选择地活在平面上,但是,心灵获得了自由。愿意升起你的心灵吗?
每个人都是独一无二的,而且我们永远只能是自己,卢梭说的,对于整个世界我微不足道,但是我对于自己确是全部。事实上我们只对于自己重要,如果我死掉了,没有几个人会在三年后保持对我的记忆,如果我痛苦,没有几个人会有真正的同情,因为太难了,每个人都无法了解我的意识。所以我们要独立,活着就是成为自己,那个独一无二的自己,去寻找自内在的完美与和谐,去实现句那没有选择的话:I am who I am。Simply because I am not and can not be anyone else.可是我们受教育,教育的目的就是教我们忘掉自己,去变成一个称为标准的人,不是这样吗?从小学起我们就要评三好,树标兵,学雷锋,学赖宁。老师总是看到我们的恶习,“你那样子不合行为规范,不可耻吗?” 到了大学,我们又自由了多少呢?我们依旧看别人,看典型,看所谓成功者,我们依旧活在要忘掉自己的标准包围中,去bbs看看,似乎所有人都统一了口吻,GRE 2400,拿了牛校offer, 签了著名外企,找到了ppmm, 牛啊,羡慕啊,爽啊, 历史走到了21世纪,北大和清华人只剩下一副面孔了,每年招了很多新生,最后就剩下了一个。
比较是有意义的吗?作为一个独一无二的存在,作为自己的全部主宰,为什么要什么都和人家比才可以找到意义?为什么当别人考G的时候,我也一定要考,为什么考不过2200就要郁?为什么billgates 成功的时候,我也一定要学计算机?可是自己和别人是多么的不同,些不同难道可以在一些欲念的驱动下轻易的忽略?
崇拜是有意义的吗?明星是需要那样追捧的吗?中国的那支烂球队是需要那么多关注的吗?
当我们倾注希望的时候,他们借此赚到了更多的银子,活得更加嚣张,更加让我们失望,我们是在给富翁们献爱心,爱心那么多,为什么不献给需要爱心的更多的人们,为什么不献给自己,独一无二的自己?
当我们崇拜自己,热爱自己,追捧自己,关注自己,我们就都也是明星了。这样盲从将无法发生,起哄将无法发生,个人崇拜将无法发生。这个意义大的很,至少大跃进将不发生,文革将不发生,我们的经济有可能早三十年走上正轨,现在我们不需要拼命飞跃重洋,中央到地方的官员就不要象现在一样,在亿万人没有工作时还竭力吹嘘7%的GDP增长,就像阳痿的人,为了脸面,郑重地去声名:请看我浓密的胡须,年增长率7%
]]>一篇好文。直指中国教育的病根。文章提到的一些想法自己也思考过,只是没有文中说的这么透彻。很多东西只是自己一些模糊的想法,看到文章豁然开朗。总结一下,文章说了几个东西:
]]>
一、关于基础
CSDN:你在系列文章最后分享了9点心得体会,总结当时到现在的这段时光,是否有新的感悟分享?
张龙:我现在依然在坚守着这些体会:
基础的重要性。我总是不断强调基础的重要性,因为我是有切身体会的。基础的东西可以让你受用一生。struts出来了,webwork出来,tapestry出来了,jsf出来了,struts2也出来了,等等等等。但是这些框架或者标准都是新东西吗?其实每个人都知道并不是的,他们都是基于HTTP协议的,换句话说都是构建在jsp与servlet基础之上的,有很多人连这两个基础都没掌握好,就去学这些框架,这真是难以想象的。有了好的基础会让你学习新东西更快,也更扎实,走的也更远,否则你永远都是在跟着别人的脚步。
还是基础。我们都知道Spring是非常优秀的框架,也是很多公司采用的技术选型。但是你是否真的了解Spring的核心IOC与AOP了吗?适当看些设计模式的书会让你受益匪浅。其实你只要掌握了java的动态代理对于AOP的理解就是自然而然的事情了。
舍得投入。 有时间的话买些书看看,好书可以让你系统的学习一些技术,而不是一些支离破碎的技术点。
抓紧时间。 将游戏的时间控制的少一些,把精力放在学习上吧,如果你想投身IT行业,做好不断学习的准备
要有激情。 没有激情的人生是惨淡的人生。生活和学习要有激情,否则你体会不到淋漓尽致的快乐与苦痛。
要有耐心。 没有耐心是无法成为一个优秀的程序员的。其实写程序的时候大部分时间是与错误、异常相伴的,不要幻想一下就能将程序写对,优秀的程序实际上是不断重构的过程。
要能耐得住寂寞。 很多时候我们都是与计算机为伴的,如果你没有对程序的兴趣与热情,时间长了你会坐不住的。
8.英语的重要性,如果你想进外企的话,那么英语是必须要过的一关(主要体现在听说上)。
基础的东西总是最重要的。
二、关于自学(经验)
CSDN:在(中)篇里,你提及上大学最大的两个收获就是:决定了自己的人生方向和掌握了自学的方法。你对现在正处在大学里的准程序员们有何建议?
张龙:我始终认为这是我大学期间最大的两个收获。因为进入大学后就意味着要独立承担自己的一切,别人可以给你建议,但最后拿主意的一定是自己。特别是对于计算机专业来说,自学意味着一切。毕竟计算机领域涉及众多,学校上课讲的只是最基本和基础的,在掌握了这些内容之后剩下的就要靠自己了。
现如今,互联网上的资源一应俱全,你要的东西网上基本都能找到,比我那个时代好太多了。不过,这是一个最好的时代,也是一个最坏的时代。可能你需要的很多资源都需要翻墙才能获取,这应该是每个程序员的必备技能了。另外,对于在校学生来说,有机会可以兼职或是去公司实习,这样可以尽早步入社会,了解公司都需要什么,为今后的工作提前做好铺垫。
关于压力
CSDN:你在研究生的时候做过柯尼卡—美能达公司的经销商管理系统、一个游戏点卡的销售网站,都给了你不小的压力,你是如何对待压力的?
张龙:压力每个人都有,做事情如果没有压力其实很容易造成拖延。这种压力一方面来自于自身,另一方面则是外界施加的。适度的压力会激发人的潜能,我现在在做事情的时候就喜欢给自己设定一个截止日期,算是自己给自己的压力吧。没有压力可能一件事,特别是需要长时间付出的事情永远也做不完。
三、关于沟通(经验) CSDN:你在研究生期间就给人讲授课程,锻炼自己的口语表达能力,不少程序员相对比较内敛,这方面你有什么经验可分享?
张龙:我觉得这是个循环问题。你越闭塞,越不想与人交流,那你就越陷在自己的圈子当中,不愿走出来。反过来说,当你走出去,多多参与讨论,多多与人沟通,这对你的思维也是很好的锻炼,你就知道该如何与人打交道。你永远不是一个人在战斗,走出去才能实现更好的腾飞。
四、关于学习(建议) CSDN:在你一路走来,遇到一些浮躁的心境时是怎么处理的?对刚进入这个领域的人有何建议?
张龙:浮躁、烦恼每个人都有,也不光是程序员才会这样,各行各业的人都会遇到各种各样的问题。适当排解很重要,憋在心里只会把人憋疯,出去找朋友喝喝酒、唱唱歌,一切都会过去的。我不是专家,不敢给人提建议,只是觉得学习是保证你今后的路越走越宽的最佳手段。
来源: <http://www.csdn.net/article/2013-08-21/2816646>
另:一个文章摘录
程序员最重要的技能 火龙果软件 发布于 2013-8-22 什么才是程序员最有价值的技能?怎样才能成为一名成功的开发者呢?我敢打赌,在你的职业生涯中你至少问过自己一次这样的问题。你找到答案了吗?你认为自己搞清楚了没有? 许多年轻的程序员会告诉你,伟大的开发者最重要的技能是对自己所用语言的掌握。当然,你得对 C/#、 F/#、C++、Java、Ruby、Haskell 或什么别的语言娴熟于心。然而,语言本身并不能提供足够的技能让你完成桌面或 web 应用。 “那要不就是对平台的知识了,”你又问自己。也许甚至是整个平台体系,如果你仔细思考一下的话。比方说,这有可能意味着要知道 Windows API 或 iOS 开发的工具或库。可是,你再想一下。如果趋势变了的话又会怎样?如果项目转向另一个平台的话又会怎样?如果你只具备前一个平台的知识的话,你还会是一名伟大的程序员吗?我不这么认为。 “对!我知道了。肯定是解决问题和分析性思维的能力”,你几乎对着我吼起来了。事实上你是对的。没有一个好的开发者是不具备分析性思维的。但是,问题解决仍然不是你应该具备的最重要技能。 “如果不是编程知识的话,那一定就是编程激情。你每天都得学点新东西。不能停止,你得热爱它。”的确,你是对的,尽管这并非最重要的能力,但已经接近了。让你从好的开发者变成伟大的开发者的,是编程的激情,尤其是学习的激情。 然而,还有一个技能更有价值,那就是沟通。 许多时候这一点被低估了,可如果不使用沟通技能的话你一天都过不了。而且,你要沟通的还不仅仅是客户。还包括你的同事,分享你的想法,用不侮辱人的方式辩论,说服你的老板应该采取你的方式。此外,还有还要汇报状态更新,解释发生的事情。你每天都要沟通,而且要沟通得当,如果你要成为伟大的开发者的话。 这就是我要发文章谈演讲这个似乎不相干话题的原因。我认为从中你可以学到很多东西,如果你对此感兴趣的话你可以继续学习 coursera 的课程(英文)。
来源: [http://www.uml.org.cn/itnews/2013082209.asp](http://www.uml.org.cn/itnews/2013082209.asp)
]]>2013年3月11日 陈皓
读了《Rework》这本书好多遍,每次读都有不同的感想。但从来没有把这些感想记录下来,今天把《Rework》书中的一些章节做一些摘录,并把我的一些感想总结出来。供大家参考。这是一本平生以来让我中毒很深的书,也是一本让我思考得很多的书。希望看到这篇文章的人都能好好地读读这本书。这本书并不难读,是一本你可以一口气不中断就可以读完的书。
“这在现实世界里面行不通”,当你向人们介绍一个新创意时,人们总是这么回答你。这个“现实世界”听起来如此令人沮丧,……只有人耳熟能详,习以为常的事情才会胜利,即使是这些事情已经漏洞百出陈腐低效。
揭开“现实世界”这个锅盖,你会发现居住在里的人都充斥着悲观主义和失望的情绪。更糟的是,他们想将别人拖进他们的坟墓。如果你是充满希望和野心的人,他们会试着说服你,你的想法是不可能的。他们会说你在浪费时间。
“现实世界”并不存在,那只是人的一个借口。只是某些人为了开脱 自己的无所作为,跟你一点关系也没有。 感想:我经常会向一同事和朋友提及一些我的想法,朋友同事们经常会回答我——这个事某某人,某某团队做过了,没成功。或是对我说,你做这个事的时候,要小心这个要小心那个。我觉得,这个时候是最考验我们的时候了,要有一个清醒的头脑去分析别人的话,别人真不代表自己。这个世界上大多数人都是比较保守的,大多数都对这个现实世界都有或多或少的恐惧感。当然,你可以选择做大众,但是如果你想让你的人生有些不同,有些精彩,我还是建议你不要和大多数人想得一样,如果你和大多数人的想法一样,你必然会和大多数人一样的平庸。当然,如果你和大多数人不一样,你要么就是天才,要么就是傻瓜。要证明你自己是不是傻瓜,我们可以看看我们过去有没有过一些小成功或小成绩。如果有,那么就应该大胆地坚持自己的想法。
你真的从错误和失败里面学到什么了吗?你也许学到了别再重蹈覆辙,但是这有什么意义吗?你仍然不知道接下来该做什么。
相反的应该从成功中汲取养分。成功給予真正靠得住的教材。
失败并不是成功的先决条件。自然规律是,逗留在过去的失败中是无法进化的,进化是建立在成功的基础上的。 感想:我见过和很多人都在抱怨这不好那不好,但是他们其实并不知道什么是好的,因为——没有见过好的,你将永远不知道什么是好的。就好像你没有见过什么是汽车,你就只会整天在抱怨为什么骑自行车太累。回头想想我们的编程的这个过程也是一样,我们编程技能的提高基本上都是在看到别人的那些漂亮优雅的代码。所以,你一定要去看看那些优秀人干是怎么想的,怎么干的,去那些成功的公司开开眼界。另外,你应该多想想你过去做成功过什么事?那些才是你的长处,才是让你进化的前提。
除非你是算命先生,长期的商业计划是种幻想。有太多的事实证明那是超出你的掌控的:市场环境、对手、顾客、经济等等。做计划让你觉得一切尽在掌握但实际上你没有。
当你把计划变成猜测时,就等于进入一个危险的境地。做计划就是在用过去推导未来,等于给你戴上了眼罩。 感想:你有职业规划吗?如果你有的话,那么你就一定就错了。职业规划是一件很扯淡的事情。我和一些高手都交流过,其实这些人在当初都并不有什么职业规划的,要说有的话,也就是想把技术搞透搞精。这些人在一开始从来没有想过要当个什么经理或是什么架构师之类的东西,这些人就是对技术有非常大的热情,把身边的那些看得见够得着的事情做到好好地,并且保持不持续强大的好奇心努力地学习自己不懂的东西。一个坚定不移的决定和意志力会比任何的计划和职业规划都重要。你问问自己,想不想当程序员,能不能一辈子都当一个程序员,能不能写程序写一辈子?(关于做一辈子程序员这个事,大家可以看看我的新浪微博 ——没哪个行业能像计算机行业这么活跃、刺激和有趣了。不仅是新兴工业革命的主力,又渗入到所有的行业中,干一辈子值了。//@_你亲爱的偏执狂: 程序员首先是工程师,Professional,就跟律师,医生一样,给大家解决问题;但是另一面呢,又是艺术家,创造新奇好玩的东西。这样的职业做一辈子有什么问题?)
规模越大你就得承受更大压力、需要更专业、拥有更强的能力。
有没有注意到,一个小公司希望自己变大时,大公司却想要变得灵活变通。记住,一旦你变大了就很难在不解雇人、不破坏士气、不改变你的整个商业路线的情况下收缩规模。
扩张不必成为你的目标。我们也不是仅在讨论你已有员工数。 还有花费、租金、IT 基础结构、设备等。这些事情不会碰巧发生。 你来决定是否承受这些。如果你决定去承受,你也将遇到新的头痛问题。花费那么多,你强迫自己构建一个复杂的生意,有一大堆困难而高压的事情要解决。
小公司并不是一个起步,小公司本身就是一个伟大的目标。 感想:很多人都会以为拥有一支成百上千人的团队而成为一个成功的标志。就像很多朋友和猎头都会问我管多少人,当我说,我就管个十人不到的团队时,他们似乎都会觉得我很平庸。他们中的一些人基本上就不会再问我在干些什么了,因为他们可能觉得这么少的人都干什么大事呢?。当然,我说了他们也不一定听得懂。人多可能恰恰说明你可能在干一个劳动密集型的事情,这并没有什么可自豪的。真正自豪的不是在战争中用人海战术让大量的人去当炮灰,而是用一个小分队端掉敌军的军火库或指挥部。所以,关键不是你有多少人,关键是你做的事是不是有非凡的意义,而且你用了最小当量的资源。这就好像建立一个高性能的网站一样,用成百上千的服务器不算本事,谁用的少才是本事。
工作狂的行为不但没有必要,而且愚蠢至极。过多的工作并不代表你对项目更关注,也不代表你作了更多的贡献,这仅仅意味着你干了更多的活而已。工作狂制造的麻烦比解决的麻烦多。
工作狂往往不得要领。他们花大把大把的时间去解决问题,他们以为能靠蛮力来弥补思维上的惰性,其结果就是折腾出一堆粗糙无用的解决方案。
如果你只是为了工作而工作,那么你就会丧失判断力。你的价值 观和决策方式都是扭曲。你没有能力去判断哪些工作值得做,哪些工作该放弃,最后搞得自己筋疲力尽,而一个筋疲力尽的人是无法作出明智的决定的。
工作狂不是英雄。他们不是在节约时间而是在浪费生命。真正的英雄早已想出了办法,搞定一切,然后回家了。 感想:这让我想到了那些为了冲业绩的业绩KPI的制订者们,很多时候,他们的价值观和决策真是的很扭曲的。他们生生地把一种技术密集型的工作变成了劳动密集型。他们其实就是在拼命地训练客户需要的那匹“更快的马”,而从来没有想过要去造个更快的交通工具。
另外,每当我在优秀员工的评比和员工的绩效考核中的跨团队比较中我们能听到很多很多的人说,XX员工工作任劳任愿,工作得很晚很晚,付出很大。老实说,我真的为这样的价值观感到悲哀。最后,我还想说说关于超时工作,我也经常学习和做自己的事情到深夜,我相信很多人也这样,但我们应该认真思考一下Rework中的这个观点,我们超时工作是在使用蛮力呢?还是在使用热情和兴趣呢?
想要创造一款伟大的产品或者是某项卓越的服务,最直接、最简单的方法就是去做你自己想用的东西。设计你了解的产品——你就能很快发现它到到底好不好用。
最棒的是,“解决你实际遇到的问题”会让你爱上你做的事情。 你知道问题所在并且熟知解决它的价值。这是无法替代的。毕竟,你会充满希望的在接下来的日子里继续做。 甚至会占据你余生所有时间。所以,最好还是做自己真正关心的东西。 感想:这就是吃自己的狗食,做自己感兴趣的事。软件项目中,我最恨的就是那种闭门造车造出来的自己都不用的东西(不是从已有业务生长出来的东西),以及那些自己不动手就在边上指指点点的各种咨询师或是喜欢动用行政命令的高层管理者。
但是,在这里,我更想说说我所理解的另一层“挠自己痒处”——有天我和一前前同事聊天,她说她在那家公司十多年了,现在老了,虽然心不老还想折腾,但是对自己的能力没自信,求稳了。我听到很多朋友想对自己有个改变,比如有QA的同学想做开发,有生活在内地的朋友想来大城市的大公司里有更爽的经历,这些人明明想活得更有激情,但最终在现实面前认命妥协。我说既然有痒处,还比较痒,那就应该毫不犹豫革自己的命,轰轰烈烈地活一次。别等老了后悔当年没有勇气。“挠自己痒处”就是挑战自己,革自己的命,既然想了,就做吧,生命只有一次,值得我们轰轰烈烈地去为之付出。
人们最常用的借口是:“时间不够。”他们宣称很想开一家公司,学一种乐器,写一本书,等等,但时间不够用。拜托,如果你善加利用,时间总是有的。
把看电视或玩魔兽的时间腾出来完成你的创意;把10点上订改成11点上床,这不是怂恿你通宵达旦或是一天干足16个小时——我们要说的是,第周匀出一些业余时间来,就足够你去做些事情了。
当你拥有某种强烈的渴望时,你就能挤出时间来——不管你身上是否背负着其他责任。事实上,真相是大多数的渴望并不是那么强烈。于是他们拿时间当借口来自我开脱。别给自己错口。
另外,永远会有正当其时的时候,你总会觉得自己会么太年轻,要么太老,要么太忙,太穷,或是别的什么原因。如果你总是为遇到一个完美时机而发愁,那么,完美的时机绝对不会到来。 感想:我在“挑战无处不在”中也表达过这样的观点,关于热情和态度,说白了就是不要给自己找借口。比如:“工作忙事多没时间学所以可以不懂”,“工作中没用到所以可以不懂”,“工作没有挑战,一直没有遇到合适的项目”等等。而且,如果你只能在万事俱备的情况下才能做事,那么,你还有什么价值呢?人的价值和竞争力就是在条件并不完美的时候还能搞定事情。
坚定的信念能为你赢得超级粉丝,他们会为你马首是瞻,会舍身保护你,他们充满激情的口碑传播将胜过这世间一切的广告。
强大的主见,也是要付出代价的,在这个过程中,会有人诋毁你,说像傲慢,冷漠。没办法,这就是人生,有人喜欢你,就有人憎恨你。如果你的说法没有引起任何人的心烦意乱,只能说明你的推广力度可能还不够。(也可能代表你比较无趣)
对我们来说,我们的产品所不能处理的和我们的产品所能处理的一样令人感到骄傲。
我们的产品不适合每一个人,没有关系,我们愿意为了那些更加深爱我们的客户而放弃另一部分客户。这就是我们的立场。 感想:我从来不想做一个大众脸。酷壳上有很多比较有争议的文章,也有很多人说我很极端,偏执,有优越感,清高……,说什么的都有,无所谓。我有一个做新闻编辑的太太,主辑要求文章要客观和没有观点,不温不火,本来好好的一篇有观点的文章被编辑过后只剩下了一堆食之无味的文字。我喜欢有鲜明的观点,因为鲜明的观点和立场能不但能让文章鲜活起来,而且还能迎来更多的不同意见和更多的思考(而不只是“顶”“赞”之类无意义的回复)。我并不希望我的观点是正确的,我只希望能和更多的人加入我一同思考,而思考最佳的催化剂就是争论。我从这个行为中收益到了很多很多。
你还常常听到:“你的退出战略是什么?(万一不成功,你怎么办)”甚至在你刚开始启动时就听到它。这些人不知道怎么开始就要想到怎么结束?急什么呢?如果在全情投入之前就想怎么撤出,这种逻辑不是一般的混乱。
你正打算恋爱一场就计划着分手?你在第一次约会时就签订婚前协议?你会在婚礼早上先约见离婚律师?那也太荒谬了吧。
你需要的是承诺战略而不是退出战略。你要考虑的是你的项目怎样发展和成功,而不是怎样撤退。如果整个战略是基于撤退的,一开始你就不会有机会成功。 感想:几年前,我有一个朋友被创新工场忽悠从美国退学回来创业,我非常质疑他退学创业这个事。他对我说,没事,反正就算失败我也不会失去什么。还有一个朋友一年前从美国回国创业,也对我说,就算没搞好也没什么。我都对他们说,如果你以为用试一试的态度就可以把一个事情搞成功,那么你让这世上那些Full Time全天候从事这个事情的并有一些积累的人情何以堪?如果你创业时都想好了失败,那就说你你对这个事没有必胜的信心,也说明连你自己都不相信这个事,你还干个什么劲啊?你与其把时间用在思考如果创业没成功你会怎么办上,你还如去思考一下如何做才有更大的胜算。
“我没有足够的时间、钱、人手、经验”。不要现无谓的抱怨了。“少”不是什么坏事。“条件受限”貌似缺陷,实力优势。有限的资源能激发你在现有的条件下完成任务的能力。没有一点浪费空间,一切都需要你发挥最大的创造力。
你见过囚犯用肥皂和汤勺制作武器吗?你们是“创新”的典范。只有在条件受到限制时,我们才会发挥出“小材大用”的能力。 感想:我相信这世上很多事情都是被条件受限逼过去的。我回想到我以前经常在干的性能调优,想尽一切办法榨干系统资源这件事上,我就无法不赞同这句话。想想淘宝的TFS,就是一个因为条件受限到了不得不自己干的时候,被逼出来的东西。如果你没有足够多的人,你才会去想要怎么去优化工作和开发效率,于是才会逼着你去开发一些自动化的工具,而这些工具恰恰解放了生产力可以让你更快地干更多的事。只有条件受限,才会从劳动密集型中激发出知识密集型的东西。再回到以前我的那篇“是否需要专职的QA”一文说的到东西,如果你有很多很多帮你做测试的QA,你就不会去测试,你的团队也就不会有自动化测试等工具。这就好像在中国这个劳动力又多又廉价的大国下,基本上不需要你在技术上的创新,你只需要去不断地迁就这些低端用户,迁就这些用户越多,你还能有什么重大创新吗?真正的创新是帮助用户成长,而不是迁就用户。
同时做N件事的结果就是:一大把绝妙的点子最后被转化成一个蹩脚的产品。
有舍才有得,砍掉多余的野心,你就会发现慢慢做一件正事要胜过毛毛躁躁地做一堆傻事。
很多东西都是越简短越好。拿起斧子动手砍吧,为了一个“伟 大”的起点,让我们把那些“挺不错”地枝节给砍掉吧。 感想:这正如“为什么中国的网页设计这么烂”中说的:“中国的学生只是去记忆东西而不是真正的理解。他们从来不花时间去思考,而只是贪婪地去获取更多的信息”。与其记忆那么多的东西,还不如好好理解部分的东西。还有一种说法是:“Done is better than Perfect!”,这句话某些时候说得也挺对的,尤其是对于那些完美地长期不能Done的项目。但是Done一个Ugly的东西还不如不做。所以平衡Done和Perfect的方式正好就是这句话——“与其做个半成品,不好做好半个产品”,因为,一个半成品会让人绝望,而半个好产品会让人有所期望,这就是其中的不同。
很多公司和人都关注即将到来的大事件。他们热衷于新鲜热辣的事物,追逐最新的潮流和技术。
这是一条愚笨之路。一旦走上这条路,你就会关注时髦、放弃本质,把注意力放到不断变化的事物上,而不是持久不变的事物上。
你的事业的核心应该建立在不变的基础之上。你应该投资于那些人们现在需要,并且十年后仍然需要的事物上。
要记住,时尚会凋零。只有当你聚焦于长久的功能时,你才会发现自己把握住了永不落伍的东西。 感想:一年多前,我在《来信、创业和移动互联网》中谈到过那个时尚的“移动互联网”,说了四个方向:阅读,分享交流,电商,推荐/提醒。大家可以看到现在地铁上已经不像以前很多人都在看报纸了,而是很多人都在看手机。而手机端的社交(分享和交流),电子商务,以及很多推荐、提醒都越来越火了。这些东西都是都是“常量”——十年前存在,未来十年也会存在,我们看到很多人太过着眼于手机上的应用,而不是那些不变的因素。今天还有两个巨火无比的流行词,一个是云计算,一个是大数据,那些一听到这两个词就会兴奋的人,我不知道他们有没有真正理解这两词?他们真正理解了云计算其实就是那个N多年前就提过的IT服务,关于大数据,我完全不知道为什么会火,你会因为听到中国人口有13亿你就会兴奋吗?老鼠的数量比较这个更多呢,呵呵。其实,数据无所谓大小之分,只有好数据和烂数据之分,还热数据和冷数据之分。十年前有两个更为流行的词:一个是计算网格,一个是数据网格,这两个词5年前就凋零了,今天的云计算和大数据,有多少人意识到了其中有什么相通的,或是其中的不变因素是什么?大数据和云计算其实都在描述两个东西,一个是超大规模的计算能力,另一个则是服务。还有一个词是“平台化”,这可能被大家忽略了,通过平台进行计算和数据服务,这才是那计算机存在以来基本不变的东西,无论你是移动互联网,还是互联网,不管是云计算,还是大数据,都需要一个平台提供服务。
世人最可恨的打扰莫过于开会。原因是:
在一个小团队里,你需要的是干活的人,而不是监工。每个人都得做事,没有人可以袖手旁观 。
这意味着你在招聘中要避免招到监工型的人物,这些人喜欢对别人谆谆教导。对于小团队来讲监工型的人就是累赘。
监工们还喜欢把人拖去开会。实际上,会议是监工们最好的朋友,因为只有在开会时才显得出他们的重要。 感想:为什么会有办公室政治,那就是因为这个公司里有一部分人不干活,不做事,于是,他们就有大量地时间开始胡思乱想,他们花大量的时间不是想怎么去做事,而是想自己怎么更容易的打垮别人得到上面的认可,从而得到晋升。在大公司中这样的情况会比Startup的公司多得多。所以,如果你不想滋生办公室政治,那么你需要干两个事,第一个是最好不要变成大公司,第一个是让每个人都在实干。我最近看到其大公司,虽然很多东西不规范,而且很多东西在野蛮生长,有些事情也有点土,但绝大多数人都在实干,所以,只要每个人都在实干,就算干的方式不好,干出来的东西有问题,也比那些滋生办公室政治的公司强上几百倍
有时候,照猫画虎也是一种学习过程,就好像艺术系的学生通过临摹美术馆的作品来学习绘画。当你还是一个学生时,这种模仿是一种很有效的学习工具。不幸的是,商业战场上的模仿却不招人待见。而这也意味着你打算通过当盲从者或抄袭者的方式来建立你的事业,这注定是一个失败模式。
模仿的问题在于,简单的复制扼杀了深层的理解——而理解才能激发成长。你不但要知其然,还要知其所以然。而当你复制时,你会忽视这一点。你照搬的只是表面,而不是本质。
一旦你扬名立万,模模仿者会蜂拥而至,这就是生活。但你可以用一种绝佳的方式来保护自己不被 他们吞没:让你自己成为你的产品或服务的一部分。 感想:在《抄袭,腾讯 和 产品》中我谈到过这个事情,虽然我对抄袭和山寨很反感,但是我不得不承认这是这个世界的一部分,好的东西总是会被人复制的,这也不一定是一个坏事,这会让你更清楚认识到什么是真正产品的价值,什么是核心竞争力,你但凡有一点急功近利的想法你都要想一想那堆抄袭者,其中还不乏有钱有人的专业抄袭的公司。而面对被抄袭这样的事情,最好的解决方法是着眼着远期而不是短期——如果你着眼短期,你无疑会面对众多的抄袭和模仿者让你万劫不复,但是,如果你着眼长期,做一个3-5年需要花费大量精力才会成熟的产品,那么,那些急功近利的抄袭者会知难而退的,因为长期并不符合抄袭者的价值观。
传统智慧告诉我们,要想打败竞争者就要胜人一筹。如果人家有 4 个功能,你就得 5 个(或者 15 个,25 个)。如果人家花了$20,000,你就得花 $30,000。如果人家有 50 个员工,你就得要 100 个。
这样的冷战式的攀比思维会把人引上绝路。一旦被卷入“军备竞赛”,你就陷入了一场无止境的战争,这场战争会让你耗费大量的金钱、时间和动力。并且使你陷入长期的防御战中。处于防御状态的公司是没有预见力的;他们只能后知后觉,他们无法领跑,只能尾随。
那么你应该怎么做呢?比你的竞对手做得少,以此来打败他们。让自己去解决简单的问题,把那些纠结的、麻烦的、艰难的、讨厌的难题留给竞对手去解决。不要总想着去胜人一筹、去超过别人,试试相反的做法。
不要因为你的产品或服务不如别人的花哨就感到自惭形秽。把他们做得醒目高调,并引以为傲。就像对手那些强有力的销售他们多功能的产品一样销售你那简约的产品。 感想:一个最典型的例子就是iPad,它干得比Laptop少,比上网本少,就是一个很简单的上网和简单游戏的设备,但是他有非常简单的用户体验,让两三岁的儿童和六七十岁的老人都能很快上手。你相信吗?我花了好多年都没教会我父母用电脑以及手机里除了电话功能外的其它功能,但我只花了10分钟就教会他们使用iPad上网了。这就是“做得比对手少”的强大。只有简约的东西,才会显得更精致,才会显得更专业。
不管怎样,终究是不值得过于关注你的竞争者。为什么?因为关注别人太多会让自己受到困扰。他们现在在做什么?他们下一步呢?我们该怎样作出回应?
每一个小小的动作都会被分析一下。那是一种可怕的心态。这会产生不可抗拒的压力和焦虑。这样的想法会滋长不好的东西。
这是没有意义的事情。竞争者的风景时时在变。你的竞争对手明天一个样儿,今天一个样儿。完全在你控制之外。去担心你所不能控制的事情有意义吗?
过于关注竞争者会混淆你的视野。当你一直吸收别人思想时, 你的机会则会减少。你变得反动而不是充满想象力。你只不过是将你竞对手的产品换了个包装。
如果你打算做一个“the iPod killer”或“the next Pokemon”,你已经死了。你是在承认你的竞争者所设定的参数。你没有跳出 Apple 的套路。他们制定了这个游戏规则。你不可能打败制定规则的那个人。你必须重新制定一个规则,而不是稍微改建一点点。 感想:这个社会浮躁之处就在于我们太多的观注了别人,人比人气死人。我们很多人都注意到了别人的风光,看到别人创业被注资,看到别人找到了好的工作,看到了别人不走正道而发达,看到了别人很轻松还挣得多,甚至看到别人的粉丝比自己多,等等,等等,这些东西让自己的心态变,变得非常地不淡定了。眼红也是魔鬼,因为眼红让人心理扭曲了的例子还少吗?不要在乎别人干了什么,你应该多看看自己的长处是什么,每个人都有每个人的路,你要做的是按照自己的节奏和自己擅长的方式行事,而不是小猫钓鱼。
说“好的”很容易。我们很容易接受同意一个新功能、同意一个过于乐观的截止日期、笑纳一个平庸的设计。很快,一大堆你曾经说“yes”的事情就发生连锁反应,很多你不想要的东西越堆越高,甚至你都看不出原来想要的东西。
别相信“顾客永远是对的”这类的话。如果你是一个大厨,你的很多客人说你做的菜太咸或者太烫,你可以改。但是如果有一些挑剔的老主顾要求在宽面条里面加些香蕉,你千万不要理会他们,没关系。若是为了少数顾客的要求而毁了产品不值得。
你的目标是确保你的产品与就是和你合拍的产品,你就是你自己产品最踏实的粉丝。你是最信赖它的那个人。那样的话,你会说:“我想你也会爱它的,因为我爱它。” 感想:亨利福特说过:“如果我要问我的客户要什么,他们会告诉我他们要一匹更快的马”,所以,过份的迁就用户并不是一件好的事,相反会是一件很不好的事。互联网和电视节目一样都有一个万恶的KPI,电子节目那万恶的KPI是收视率,而互联网的万恶KPI是流量。于是很多公司为了流量开始不择手段,就像电视节目用庸俗化来提高收视率一样,我们的一些互联网产品也使用庸俗化的东西来提高流量。我们要做的是一个让人称道的有品质的产品,而不是一个只有访问量的产品。
也许你曾经见过这样的场景:一个顾客向一家公司投了很多钱。这家公司想要尽可能的取悦那个顾客。为了迎合这个客户的要求而改变自己的产品,渐渐地,你的产品就会脱离普遍客户的基础。
而且,突然有一天,这个大客户绝尘而去,公司则会背负一个包袱——这个产品是围绕着一个已经离开了的人设计的。而其他人没法用。
人在变,环境在变,你不可能满足所有人的所有要求。公司要对某一类型的客户全情投入,而不是对某个善变的客户唯唯诺诺。 感想:你永远要找到自己的定位,你不可能满足所有的人。就像屌丝们喜欢的北京的动物园批发市场和高富帅们喜欢的北京燕莎商场一样,他们分别订位于不同的用户。你的产品从生下来的那一时刻就应该需要做好定位,是面对什么样的人群。而且,你也不可能实现所有人的需求的。有时候,失去一些客户并不是坏事,我们要做的是管理我们的客户,让客户认同我们,而不是被客户牵着走。
你不会瞬间大红大紫,也不会一夜暴富,你所了解的那些道听途说的“一夜成名”的故事,深挖一点,你就能发现这些成功人士在到达引爆点之前,都已经在这个方向 上苦熬了很长时间。
把一夜成名的迷梦换成一步一个脚印的成长行动吧。道路很艰难,但你必须充满耐心。你得用功去做,在遇到伯乐前,你得努力很长时间。 感想:这和我在程序算法与人生选择一文中所说的那个最短路径的算法的类比一样,与其展望要当什么架构师或是要成为牛人的憧憬,不如把身边看得见够得着的东西学扎实,干出色。一夜成名只是一个传说,你知道酷壳是因为我写十多年的博客,你知道我是因为我积累了十多年的编程,看看酷壳以前介绍过的王平同学吧。很多事情都不是偶然的,都是有前兆的,还是我以前说过的那句话,“如果一件事情以前没有发生过,未来也不会发生”,比如:如果你在学校里,在工作里,你的同学和同事并不经常来向你请教询问你的意见,那么你基本上很难成为一个Leader。
当你把员工当孩子看时,人们就会像孩子一样行事。
当公司里事事都要上报审批时,你就创造出了一种无脑文化。你成功地制造出了老板和员工之间的对立关系。这种关系在咆哮着:“我不相信你!”
当你处处限制员工,比如禁上他们在上班时访问外部网站或是开小差,你会得到什么好处?什么也得不到。人们需要开小差,这有助于打破整日的枯燥单调,花点时间上上Youtube或Facebook不会失去什么。
如果你要监控你的员工,你得想想你要花多少时间和金钱来监管员工。你浪费了多少钱去安装监控软件?你浪费了多少人力资源去监视员工?你浪费了多少时间去写没有人会看的规章制度?看看这些成本,你很快就发现,对员工的不信任才是最大的开销。 感想:我始终在跟我的团队成员说,最有效的管理就是自己管理自己,而不是还要专们的人来管你。不然的话,你一定会很难受的。如果你能管理好你的工作和任务,我们就不需要项目经理。如果你能管理得好你的做事的方法和流程,就不需要那些搞流程的。如果你能管理得好你的程序质量,我们就不需要QA来监管你…… 等等。其实,你们如果能管理得好自己,并能自我进化。你们甚至不需要一个经理。但是,你们可能会需要一个为你们跑腿打杂的人,其实,那个人就是经理。
(全文完)
(转载本站文章请注明作者和出处 酷壳 – CoolShell.cn ,请勿用于任何商业用途)
]]>2013年3月11日 陈皓
读了《Rework》这本书好多遍,每次读都有不同的感想。但从来没有把这些感想记录下来,今天把《Rework》书中的一些章节做一些摘录,并把我的一些感想总结出来。供大家参考。这是一本平生以来让我中毒很深的书,也是一本让我思考得很多的书。希望看到这篇文章的人都能好好地读读这本书。这本书并不难读,是一本你可以一口气不中断就可以读完的书。
“这在现实世界里面行不通”,当你向人们介绍一个新创意时,人们总是这么回答你。这个“现实世界”听起来如此令人沮丧,……只有人耳熟能详,习以为常的事情才会胜利,即使是这些事情已经漏洞百出陈腐低效。
]]>
By 刘未鹏 – June 5, 2008 正儿巴经学习算法算起来也有快两个月了,之前作为计算机工科生虽然算法和数据结构是必修课,但实际上只是停留在“理解”的层面,相当肤浅,更遑论举一反三灵活运用了。因此,所谓“正儿巴经”学习算法,意即开始对算法思想的本质进行归根究底的过程、对思维方法论进行归纳抽象的过程、对各种解题技巧进行一般化的过程、通过不断练习来让记忆内隐化的过程..
在“正儿巴经”学习算法之前,我曾经有大半年时间都在用业余时间“正儿巴经”地学习心理学和认知神经科学。所以在开始正经思考算法问题之前做的第一件事情就是仔细琢磨一直令我困惑的问题——那些看似抓不到摸不着的灵感到底是怎么来的。
现代心理学的一个最伟大的原则就是:所有的心理活动同时都是生理活动。——实际上,“心理活动”只不过是“大脑神经活动”的通俗称呼。虽然大脑的结构极度复杂,然而许多人不知道的是,现代神经科学对大脑功能从高层原则上的认识已经可以说是相当完备了,而对于记忆和学习这块更加是因为Eric Kandel的突破性工作变得相当清晰。可以说剩下的工作主要就是补充细节了。于是乎,借助于三本关于记忆和学习的书,一本专门论述解题心理学的书,wikipedia,波利亚的三卷解题书,以及自己在思考有限多的问题的过程中对自己的思维过程的反省和总结,我试着对解题的心理学做了一个思考和总结(《跟波利亚学解题》)。——这听起来很奇怪,一个本身只会初级算法的人又如何去思考涵盖所有问题解决的思维过程呢?还是引用波利亚著名的发明者悖论吧:有时候,一个一般性的问题反而要比它的一个特例更好解决。
然而,一般性的问题思考清楚了,清楚解题思维的本质了,并不代表我就万能了,就立即擅长解决所有算法问题了。解题不是光靠思维的,巧妇难为无米之炊。事实上,在《跟波利亚学解题》中总结的一个非常关键的要点就是:启发法固然可贵,然而知识的重要性是不可替代的。不存在通用的、万能的知识,要不然我们也不必到今天还在不断探索物质世界的规律了。此外,获得知识的过程——学习——本质上是个体力活(尽管是有一定方法的体力活),这个体力活大致分为两步:
(关于什么是外显记忆什么是内隐记忆请参考wikipedia或者《跟波利亚学解题》)
而第二步又包含两个过程:
关于第一点有本不错的书——《学习的艺术》。
关于第二点有一个不错的例子,最初从李笑来老师的blog上读到的(《把时间当作朋友》): 我李敖看的书很少会忘掉,什么原因呢?方法好。什么方法?心狠手辣。剪刀美工刀全部下来,把书给分尸掉了,就是切开了。这一页我需要,这一段我需要,我把它分类分出来了。那背面有怎么办呢?把它影印出来,或者一开始就买两本书,把两本书都切开以后排出来,把要看的部分切开。结果一本书看完了,这本书也被分尸掉了。这就是我的看书方法。
那分类怎么分呢?我有很多自己做的夹子,夹子我写上字,把资料全部分类。一本书看完以后,全部进入我的夹子里面了。我可以分出几千个类来,分的很细。好比说按照图书馆的分类,哲学类,宗教类;宗教类再分佛教类、道教类、天主教类。我李敖分的更细了,天主教还可以分,神父算一类。神父还可以细分,神父同性恋就是一类,神父还俗又是一类。修女同性恋是一类,修女还俗这又是一类。
任何书里有关的内容都进入我的资料里来。进入干什么呢?当我要写小说的时候,需要这个资料,打开资料,只是写一下就好了。或者发生了一个什么事件,跟修女同性恋有关系,我要发表对新闻的感想,把新闻拿过来,我的资料打开,两个一合并,文章立刻就写出来了。
换句话说,我这本书看完之后,被我大卸八块,五马分尸。可是被我勾住了,这些资料我不凭记忆来记它,我凭用细部的很耐心的功夫把它勾紧,放在资料夹子里。我的记忆力只要记这些标题就好了。标题是按照我的习惯来分,基本上都翻译成英文字,用英文字母排出来,偶尔也有些中文的。
今天我把看家的本领告诉大家,李敖知道的那么多,博闻强记,记忆力那么好。我告诉大家,记忆力是可以训练的。记忆力一开始就是你不要偷懒,不要说躺在那里看书,看完了这本书还是干干净净的,整整齐齐的,这不对。看完了这本书,这本书就大卸八块,书进了资料夹,才算看完这本书。
今天我为大家特别亮一手,把如何看书的招告诉大家。不要以为这本书看完了,干干净净的新的算看过。那个不算看过,因为当时是看过,可是浪费了。你不能够有系统的扣住这些资料,跟资料挂钩。可是找我这个方法,可以把你看过的书,都把它的精华抓出来,扣在一起。这就是我的这种土法炼钢的治学方法。
恰恰运用了记忆最深刻的原理。
我们的大脑本质上是一个计算器,其物质基础是神经网络;而不断的练习则是对该网络节点间联系强度(神经细胞间的突触联系强度)的训练。——可惜的是像爱因斯坦大脑内的经过完美训练的神经网络参数不能直接导入到我大脑中,也许将来可以做到,但目前只有笨办法,实在是件郁闷的事。
所以,拿起书吧,训练你的神经网络,路漫漫其修远兮..
参考
我在豆瓣上列了两个豆列
我是比较喜欢”方便提取记忆”的.
敖哥是否是露一手的同时,再留一手?敖哥的这些动作从本质上讲,就是资料的收集整理,但是要做到记得牢靠、记得快的话,资料的收集整理过程重要,但是记忆方法、反复复习、也很重要哇
“然而,一般性的问题思考清楚了,清楚解题思维的本质了,并不代表我就万能了”建议大家也去看看《你的知识需要管理》这本书,写得非常经典!!!!!!
李敖的这些做法有以下几点,我给出自己的看法: 1、看完书后,就需要整理,但是他给出的方法,我认为可以进行升级:对于所有纸质图书,当然可以全部录入到计算机的知识管理程序中 2、分类的方法中, 主要分类中:按照图书管理分类是正确,但是图书管理分类有其标准,叫什么《中图法》名字我忘记了 次要分类中,就是他说的细分法,我个人认为这样分类是错误的,而应该采用打标签的方式来完成 3、李敖收集什么信息,也非常值得我们研究,他收集那些信息?什么类型的信息需要收集 5、跟资料挂钩,任何信息必须要挂在已有的知识框架上面,否则这不是知识,而只是信息而已,无用
我的记忆一直很凌乱,应该训练训练了~
恩恩 高手,我同意你的想法
1.纸质书全部录入计算机,这是一项大工程,除非你有电子版,可能花的时间非常非常多,特别是经常大量阅读的人,录入时间可能远远大于阅读时间了,虽然可以加强记忆,但是,所有的书都值得这么做么? 2,他是按主题分类的,要按你的打标签法,就得列目录对标签分类对资料位置编号了,但是资料本身还是得有个规律排放吧,一篇资料可能有好几个标签,主题分类排放相比下还是可行些吧,你的方法还是计算机管理才适用.另外,方法没有特别的正确与否,最多有好有不足,我个人看法 3.可以关注 4.你说得很有道理,这也是知识系统的扩充完善过程.
刘未鹏老师,您好~一年前开始接触您的文章,反反复复阅读加上自身的思考,不知不觉收获了很多,我现在还只是一名高中生,由于自身知识储备和思维方式的不足,看您的文章难免吃力些,关于内隐记忆和外显记忆的概念,我查阅了维基百科,还有您介绍的书,还是觉得自己没有理解透彻。您可以告诉我怎样通过不断的练习把外显记忆转化为内隐记忆吗?(查阅资料说“加工深度越深,外显记忆越好。内隐记忆不存在这种情况。”,那又该怎样转化呢。。。)您在《跟波利亚学解题》一文中第五点:练习,练习也曾提到过怎样进行有效率的练习的方法,可是我没法理解那一大段话的本质含义,您可以再多给一点指导吗?如果您能抽空回答我,那我将感激不尽~谢谢
知识管理 这个话题 值得关注和学习。 和本文话题是相关的。
好好学习,天天向上!学习是一种能力——学知识、学技术的能力,但不见得每个人都能学到知识或者学到技术。理由很简单,那是因为学习方法不对。每个人有每个人的学习方法,好的学习方法值得我们大家借鉴,不过不要单纯地为了学习知识、技术而学习,还应该为了学习如何学习而学习。
]]>作者: 阮一峰
日期: 2013年5月21日
前几天,我读完的美国人 James McGregor 写的《十亿消费者》(One Billion Customers)。
James McGregor 本来是《华尔街日报》和道琼斯集团在华负责人,后来辞职经商。为了对记者生涯做总结,他就写了这本书,让西方人了解如何在中国做生意。
在书中,他通过对一些涉及高层的案例介绍,披露了中国政府商业管理的内幕,对中国社会有精准深刻的分析。很难相信,一个外国人如此懂中国。
我认为,对于想在中国经商的人,这本书是必读的。尤其是如何处理与中国政府的商业关系,大概很难找到比它更好的读物了。
此书不太可能在国内正式出版,译言网有一个网友翻译的中文版,质量相当好,推荐阅读。
下面就是我整理的一些摘录。
========================================
《十亿消费者》摘录
作者: [美] James McGregor
(题图:刘勃麟的 Hiding in the City 系列)
一、 中国文化
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.
亲吻干部,拥抱客户。
(完)