Web开发中需要了解的东西

在StackExchange上有人问了这样一个问题:What should every programmer know about web development?(关于Web开发,什么是所有程序员需要知道的?)里面给出的答案非常不错,所以,我翻译转载过来。 顺便说一下,StackExchange真是非常好,大家可以对同一个答案做贡献和修订,看看这个问题的修订过程你就知道了——专业的问答网站应该怎么去做。这就是我在这篇文章中也说过真正的用户体验是什么样的

好了,下面是正文(我对原文做了一些批注,也许不对或有误导,请大家指正)

下面的这些东西可能对于大多数人并不陌生,但是可能会有些东西你以前并没有看过,或是没有完全搞懂,甚至都没有听说过。(陈皓注:我相信当你看完这个列表后,你会觉得对于我国的Web开发有点弱了,还是那句话,表面上的东西永远是肤浅的)

接口和用户体验

  • 小心浏览器的实现标准上的不一致,确信让你的网站能够适当地跨浏览器。至少,你的网站需要测试一下下面的浏览器:

最后,你可以使用一下这个工具 来看看你的网页在不同的浏览器下是怎么被显示出来的(陈皓注:这个工具就是以前本站介绍过的在不同浏览器和平台上检查你的网站的兼容性

  • 多考虑一下人们是怎么来访问你的网站而不是那些主流的浏览器:手机,读屏软件和搜索引擎,例如:一些Accessibility的东西: WAI 和  Section508, 移动设备开发:MobiForge.
  • 部署Staging:怎么部署网站的更新而不会影响用户的访问。 Ed Lucas的答案 可以让你了解一些(陈皓注:Ed说了一些如版本控制,自动化build,备份,回滚等机制)。
  • 千万不要直接给用户显示不友好的错误信息。
  • 千万不要把用户的邮件地址以明文显示出来,这样会被爬虫爬走并被让用户的邮箱被垃圾邮件搞死。
  • 为用户的链接加上 rel="nofollow" 的属性以 避免垃圾网站的干扰。(陈皓注:nofollow是 HTML的一个属性,用于通知搜索引擎“这个链接所指向的网页非我所能控制,对其内容不予置评”,或者简单地说,该链接不是对目标网站或网页的“投票”, 这样搜索引擎不会再访问这个链接。这个是用来减少一些特定垃圾页面对原网站的影响,从而可以改善搜索结果的质量,并且防止垃圾链接的蔓延。)
  • 为网站建立一些的限制 – 这个属于安全性的范畴。(陈皓注:比如你在Google注册邮箱时,你一口气注册超过两个以上的邮箱,gmail要求给你发短信或是给你打电话认证,比如 Discuz论坛的会限制你发贴或是搜索的间隔时间等等,更多的网站会用CAPTCHA来确认是人为的操作。 这些限制都是为了防止垃圾和恶意攻击)
  • 学习如何做 Progressive Enhancement. (陈皓注:Progressive Enhancement是一个Web Design的理念,如:1)基础的内容和功能应该可以被所有的浏览器存取,2)页面布局的应该使用外部的CSS链接,3)Javascript也应该是外部链接还应该是 unobtrusive 的,4)应该让用户可以设置他们的偏好)
  • 严重关注Accessibility。因为这是法律上的需求(陈 皓注:Section 508是美国的508法案,其是美国劳工复健法的改进,它是一部联邦法律,这个法律要求所有技术要考虑到残障人士的应用,如果某个大众信息传播网站,如果 某些用户群体(如残疾人)浏览该网站获取信息时,如果他们无法正常获得所期望的信息(如无法正常浏览),那可以依据相关法规,可以对该网站依法起诉)。 WAI-ARIA 为这方面的事提供很不错的资源.

安全

  • 在网上有很多关于安全的文章,但是 OWASP 开发指导 涵 盖了几乎所有关于Web站点安全的东西。(陈皓注:OWASP(开放Web应用安全项目- Open Web Application Security Project)是一个开放的非营利性组织,目前全球有130个分会近万名会员,其主要目标是研议协助解决Web软体安全之标准、工具与技术文件,长期 致力于协助政府或企业了解并改善网页应用程式与网页服务的安全性。OWASP被视为Web应用安全领域的权威参考。2009年下列发布的美国国家和国际立 法、标准、准则、委员会和行业实务守则参考引用了OWASP。美国联邦贸易委员会(FTC)强烈建议所有企业需遵循OWASP十大WEB弱点防护守则)
  • 永远不要相信用户的输入(包括Cookies,因为那也是用户的输入)
  • 对用户的口令进行Hash,并使用salt,以防止Rainbow 攻击(陈皓注:Hash算法可用MD5或SHA1等,对口令使用salt的意思是,user 在设定密码时,system 产生另外一个random string(salt)。在datbase 存的​​是与salt + passwd 产的md5sum 及salt。 当要验证密码时就把user 输入的string 加上使用者的salt,产生md5s​​um 来比对。 理论上用salt 可以大幅度让密码更难破解,相同的密码除非刚好salt 相同,最后​​存在database 上的内容是不一样的。google一下md5+salt你可以看到很多文章。关于Rainbow 攻击, 其意思是很像密码字典表,但不同的是,Rainbow Table存的是已经被Hash过的密码了,而且其查找密码的速度更快,这样可以让攻击非常快)。使用慢一点的Hash算法来保存口令,如 bcrypt (被时间检证过了) 或是 scrypt (更强,但是也更新一些) (12)。你可以阅读一下 How To Safely Store A Password(陈皓注:酷壳以前曾介绍过bcrypt这个算法,这里,我更建议我们应该让用户输入比较强的口令,比如Apple ID注册的过程需要用户输入超过8位,需要有大小写和数字的口令,或是做出类似于这样的用户体验的东西)。
  • 使用 SSL/HTTPS 来加密传输登录页面或是任可有敏感信息的页面,比如信用卡号等。
  • 知道如何对付session 劫持。(陈皓注:请参看wikipedia的这Session Hijacking,)
  • 保持你的系统里的所有软件更新到最新的patch。
  • 确保你的数据库连接是安全的。
  • 确保你能了解最新的攻击技术,以及你系统的脆弱处。

性能

  • 优化页面 —— 不要使用20KB图片来平铺网页背景。(陈皓注:还有很多网页页面优化性的文章,你可以STFG – Search The Fucking Google一下。如果你要调试的话,你可以使用firebug或是chrome内置的开发人员的工具来查看网页装载的性能)
  • 学习如何 gzip/deflate 网页 (deflate 更好).
  • 把多个CSS文件和Javascript文件合并成一个,这样可以减少浏览器的网络连数,并且使用gzip压缩被反复用到的文件。
  • 为那些小的图片使用 CSS Image Sprites,就像工具条一样。 (参看 “最小化 HTTP 请求” ) (陈皓注:把所有的小图片合并成一个图片,然后用CSS把显示其中的一块,这样,这些小图片只用传输一次,酷壳的Wordpress样式的那个RSS订阅列表中的小图标就是这样做的)
  • 繁忙的网络应该考虑把网页的内容分开存放在不同的域名下。(陈皓注:比如有专门的图片服务器——图片相当耗带宽,或是专门的Ajax服务器)
  • 静态网页 (如,图片,CSS,JavaScript,以及一些不需要访问cookies的网页) 应该放在一个不使用cookies的独立的域名下,因为所有在同一个域名或子域名下的cookie会被这个域名下的请求一同发送。另一个好的选择是使用 Content Delivery Network (CDN).
  • 使用单个页面的HTTP请求数最小化。
  • 为Javascript使用 Google Closure Compiler 或是 其它压缩工具(陈皓注:压缩Javascript代码可以让你的页面减少网络传输从而可以得到很快的喧染。注意,并不是所有的工具都可以正确压缩Javascript的,Google的这个工具甚至还可以帮你优化你的代码)
  • 确认你的网站有一个 favicon.ico 文件放在网站的根下,如 /favicon.ico浏览器会自动请求这个文件,就算这个图标文件没有在你的网页中明显说明,浏览器也会请求。如果你没有这个文件,就会出大量的404错误,这会消耗你的服务器带宽。(陈皓注:服务器返回404页面会比这个ico文件可能还大)

SEO (搜索引擎优化)

  • 使用 “搜索引擎喜欢的” URL,如:使用 example.com/pages/45-article-title 而不是 example.com/index.php?page=45 (陈皓注:这里的URL是说Wordpress的,后者是默认的)
  • 如果你的动态页面要使用 # ,那么请把其改成 #! ,而在服务端,你需要处理$_REQUEST["_escaped_fragment_"] 这是Google搜索引擎需要的。换句话说,./#!page=1 会被Google搜索引擎转成 ./?_escaped_fragments_=page=1。 (陈 皓注:通常来说URL中的#后的东西都不会被传到服务器上,所以,为了要让Google可以抓取AJAX的东西,你需要使用#!,而Google会把 “#!”转成“_escaped_fragment_”来向服务器发请求,Twitter的大量的链接者是#!的,比如:https://twitter.com/#!/your_activity)。另外,用户也许会使用Firefox 或 Chromium, history.pushState({"foo":"bar"}, "About", "./?page=1"); 是一个很不错的命令。所以,就算是我们的地址栏上的地址改变了,页面也不会重新装载。这可以让你使用 ? 而不是 #! 也能无刷地保住当前的动态的页面,这可以让AJAX的请求被浏览器记住。
  • 别使用 “click here” 这样的链接。这样一来,无法SEO,而且对于一些需要使用读屏人来说很不友好(陈皓注:关于读屏软件,可参看本站的“如果看不见你还能编程吗”)
  • 了解 robots.txt 和搜索引擎爬虫是如何工作的。
  • 重定向请求 (使用 301 重定向网站) ,如果你要把 www.example.com 定向到 example.com(或是其它的变更) 这样可以防止Google的rank因为域名的变化发生改变。(陈皓注:301重定向一般用作域名变更)
  • 知道并不是所有的爬虫都是好的,有些爬虫的行为并不好。(陈皓注:比如向你的网站发大量的请求导致服务器性能低下)
  • 如果你有一些非文本的内容需要在 Google’s sitemap  中,比如视频什么的。Tim Farley的答案,可以让你看到很多有价值的东西。

技术

  • 理解什么是 HTTP 比如 GET, POST, sessions, cookies等,了解什么是 “stateless” 无状态。
  • 让你的 XHTML/HTML 和 CSS 符合 W3C 规范,并确认他们都是 合格的。我们的目标是避免浏览器的 “quirks mode”,并且可以让其更容易地能和非标准的浏览器工作,比如读屏器或移动设备。
  • 理解浏览器是怎么处理 JavaScript 的。(陈皓:你会看到有些Javascript代码在页面上前面,有些则是在后面,所以你需要对其了解清楚为什么是这样)
  • 了解浏览器是怎么装载 JavaScript,CSS和其它资源的,了解其对视觉上的影响。(陈皓注:10年前我做网页的时候因为HTML还很弱,所以只能使用table来布 局,使用table布局的问题就是整个table读完后页面才会显示,用户的视觉体验并不好)。在某些情况下,你可能需要把你的脚本放在页面的后面
  • 理解 JavaScript 的 sandbox 是怎么怎么工作的,尤其是你想使用iframes。
  • 请注意 JavaScript 可能会被禁止,这样会让你的AJAX失效。就算是大多数用户都开启了Javascript功能,但是也可能在一些情况下脚本是不被运行的,比如移动终端上,搜索引擎抓网页的时候也并不会执行你的脚本。
  • 尽可能多地学习你的部署平台。(比如:操作系统,Web Server:Apache/Nginx,防火墙,数据库,等等)
  • 把视觉效果和JS框架合在一起讨论,考虑使用一个Service,如:Google Libraries API 来装载框架,这样可以让浏览器可能早就把这个JS框架已经cache了而不需要再从你的网站上下载了。

Bug fixing

  • 明白你会花20%的时间写代码,而80%的时候在维护,所以你要小心编码。(陈皓注:参看本站的“多些时间可以少些代码”一文)
  • 设计一个好的错误报告机制。
  • 设计一个入口可以让人们联系到你并给你建议和批评。
  • 为你开发的东西形成文档,这样可以让后来的人容易维护你的软件和系统。
  • 频繁备份(也可确保你的这些备份功能正常) Ed Lucas 的回答 有一些忠告。你还需要有一个恢复策略,而不只是一个备份策略。
  • 使用一个版本控制系统来保存你的代码,如: Subversion 或 Git.
  • 别忘了做Acceptance Testing,使用 Selenium 能帮到你。
  • 确保你有足够的日志,你可以使用 log4j, log4n 或 log4r。如果出了问题,这是可以让你快速找到问题的方式。
  • 当你写日志的时候,确保你记录了你捕获了处理和未处理异常。报告和分析日志可以让你知道你网站的问题。

这里有多的东西被省略了,并不是因为那些可能不是有帮助的答案,而是因为那些东西都太细节了,超出了这个问题的范围,因为这本来就是一个Web开发 需要了解东西的Overview。我想你可以去看一下其它人的答案,我有时间,我也会补充别人的答案进来。请随意编辑这个答案,因为可能有些东西忘了,也 有可能有些东西不对。

(全文完) 酷壳 – CoolShell.cn 作者:陈皓

【经典问题】现代操作系统经典问题回顾(哲学家就餐问题C#实现)

 在1971年,著名的计算机科学家艾兹格·迪科斯彻提出了一个同步问题,即假设有五台计算机都试图访问五份共享的磁带驱动器。稍后,这个问题被托尼·霍尔重新表述为哲学家就餐问题。这个问题可以用来解释死锁和资源耗尽。

哲学家就餐问题描述:五个哲学家围坐在一张圆桌周围,每个哲学家面前都有一盘通心粉。由于通心粉很光滑,所以需要两把叉子才能夹住,相邻两个盘子之间放有一把叉子。哲学家的生活中有两种交替活动时段:即吃饭和思考(一种抽象而已)。当一个哲学家觉得饿了时,他就试图分两次去取其左边和右边的叉子,每次拿到一把,但不分次序。如果成功地得到了两把叉子,就开始吃饭,吃完后放下叉子继续思考。问题是为哲学家写一段描述其行为的程序,且决不会死锁。

源码:

哲学家就餐问题

// ************************************************************
// 在1971年,著名的计算机科学家艾兹格·迪科斯彻提出了一个同步问题,
// 即假设有五台计算机都试图访问五份共享的磁带驱动器。稍后,这个问
// 题被托尼·霍尔重新表述为哲学家就餐问题。这个问题可以用来解释死
// 锁和资源耗尽。
// 
// 哲学家就餐问题描述:五个哲学家围坐在一张圆桌周围,每个哲学家面
// 前都有一盘通心粉。由于通心粉很光滑,所以需要两把叉子才能夹住,
// 相邻两个盘子之间放有一把叉子。哲学家的生活中有两种交替活动时段:
// 即吃饭和思考(一种抽象而已)。当一个哲学家觉得饿了时,他就试图
// 分两次去取其左边和右边的叉子,每次拿到一把,但不分次序。如果成功
// 地得到了两把叉子,就开始吃饭,吃完后放下叉子继续思考。问题是为
// 哲学家写一段描述其行为的程序,且决不会死锁。
// 
// ************************************************************

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace DiningPhilosophers
{
    
/// <summary>
    
/// 哲学家就餐问题是现代操作系统中很经典的问题。
    
/// 一个哲学家的封装。
    
/// </summary>
    public class Philosopher : WorkerThread
    {
        
public const int READY = 0;
        
public const int EATING = 1;
        
public const int THINKING = 2;
        
public const int FINISHED = 3;

        
public Philosopher(object data) : base(data) { }
        
public delegate void StateSwitchedHandler(Object sender, StateSwitchedEventArgs args);
        
public event StateSwitchedHandler StateSwitch;

        
protected override void Run()
        {
            PhilosopherData pd 
= (PhilosopherData)Data;
            Ran
dom rnd 
= new Random(pd.PhilosopherId);
            StateSwitch(
thisnew StateSwitchedEventArgs(READY, pd));
            WaitHandle[] forks 
= new WaitHandle[] { pd.LeftFork, pd.RightFork };

            
while (pd.TotalFood > 0)
            {
                
// 如果两边的哲学家有拿着叉子的,则等待。 
                WaitHandle.WaitAll(forks);
                
// 否则,开始吃通心粉。 
                StateSwitch(thisnew StateSwitchedEventArgs(EATING, pd));
                
// 饭吃掉一部分移除。 
                pd.TotalFood -= pd.AmountToEat;
                Thread.Sleep(rnd.Next(
1001000));// 模拟正在吃通心粉

                StateSwitch(
thisnew StateSwitchedEventArgs(THINKING, pd));
                
// 放下左边和右边的叉子开始思考。 
                pd.RightFork.ReleaseMutex();
                pd.LeftFork.ReleaseMutex();

                Thread.Sleep(rnd.Next(
1001000));// 模拟正在思考
            }

            
// 至此,通信粉都吃完了。 
            StateSwitch(thisnew StateSwitchedEventArgs(FINISHED, pd));
        }
    }

    
/// <summary>
    
/// 哲学家相当于一个线程,这是工作线程抽象类,作为对线程操作的封装。
    
/// </summary>
    public abstract class WorkerThread
    {
        
private object _threadData;
        
private Thread _rawThread;

        
public object Data
        {
            
get { return _threadData; }
            
set { _threadData = value; }
        }

        
public WorkerThread(object data)
        {
            _threadData 
= data;
        }

        
public WorkerThread()
        {
     &
nbsp;      _threadData 
= null;
        }

        
public void Start()
        {
            _rawThread 
= new Thread(new ThreadStart(this.Run));
            _rawThread.Start();
        }

        
protected abstract void Run();
    }

    
/// <summary>
    
/// 封装哲学家数据的结构。
    
/// </summary>
    public struct PhilosopherData
    {
        
public int PhilosopherId;   // 代表哲学家
        public Mutex RightFork;     // 代表右边的叉子
        public Mutex LeftFork;      // 代表左边的叉子
        public int AmountToEat;     // 吃掉的通心粉
        public int TotalFood;       // 盘中的总的通心粉
    }

    
/// <summary>
    
/// 事件:用来通知外部现在哲学家的状态。
    
/// </summary>
    public class StateSwitchedEventArgs : EventArgs
    {
        
public int type;
        
public PhilosopherData philosopherData;
        
public StateSwitchedEventArgs(int t, PhilosopherData pd)
        {
            type 
= t;
            philosopherData 
= pd;
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace DiningPhilosophers
{
    
class Program
    {
        
static void Main(string[] args)
    
    {
            
// 准备数据
            Mutex[] forks = new Mutex[N];
            
for (int i = 0; i < N; i++)
            {
                forks[i] 
= new Mutex(false);// 开始时叉子放在桌子上,没有哲学家拿到。
            }

            Philosopher[] p 
= new Philosopher[N];
            
for (int i = 0; i < N; i++)
            {
                PhilosopherData pd;
                pd.PhilosopherId 
= i;
                pd.RightFork 
= forks[(i + 1% N];// 右边的叉子编号
                pd.LeftFork = forks[(i + N  1% N];// 左边的叉子编号
                pd.AmountToEat = N_EAT;// 暂时大锅饭,大家都一样。
                pd.TotalFood = N_TOTAL;// 暂时大锅饭,大家都一样。
                p[i] = new Philosopher(pd);
                p[i].StateSwitch 
+=
                    
new Philosopher.StateSwitchedHandler(
                        (sender, data) 
=>
                        {
                            Console.WriteLine(
Philosopher:{0} IS {1}.,
                                data.philosopherData.PhilosopherId,
                                TranslateState(data.type));
                        });
            }

            
for (int i = 0; i < N; i++)
                p[i].Start();

            Console.ReadKey();
        }

        
private static string TranslateState(int state)
        {
            
switch (state)
            {
                
case Philosopher.READY:
                    
return READY;
                
case Philosopher.EATING:
                    
return EATING;
                
case Philosopher.THINKING:
                    
return THINKING;
                
case Philosopher.FINISHED:
                    
return FINISHED;
                
default:
                    
throw new Exception(*NOT* FOUND.);
            }
        }

        
public const int N = 5;// 哲学家或叉子数目。
        public const int N_EAT = 2;// 每次吃掉的通心粉数量。
        public const int N_TOTAL = 20;// 盘中通心粉总数。
    }
}

 

运行结果:

Philosopher:0 IS READY.
Philosopher:0 IS EATING.
Philosopher:1 IS READY.
Philosopher:1 IS EATING.
Philosopher:3 IS READY.
Philosopher:2 IS READY.
Philosopher:4 IS READY.
Philosopher:1 IS THINKING.
Philosopher:4 IS EATING.
Philosopher:0 IS THINKING.
Philosopher:3 IS EATING.
Philosopher:3 IS THINKING.
Philosopher:4 IS THINKING.
Philosopher:2 IS EATING.
Philosopher:1 IS EATING.
Philosopher:1 IS THINKING.
Philosopher:3 IS EATING.
Philosopher:2 IS THINKING.
Philosopher:4 IS EATING.
Philosopher:3 IS THINKING.
Philosopher:0 IS EATING.
Philosopher:4 IS THINKING.
Philosopher:1 IS EATING.
Philosopher:1 IS THINKING.
Philosopher:4 IS EATING.
Philosopher:0 IS THINKING.
Philosopher:3 IS EATING.
Philosopher:4 IS THINKING.
Philosopher:2 IS EATING.
Philosopher:2 IS THINKING.
Philosopher:4 IS EATING.
Philosopher:3 IS THINKING.
Philosopher:0 IS EATING.
Philosopher:0 IS THINKING.
Philosopher:3 IS EATING.
Philosopher:4 IS THINKING.
Philosopher:3 IS THINKING.
Philosopher:1 IS EATING.
Philosopher:2 IS EATING.
Philosopher:2 IS THINKING.
Philosopher:0 IS EATING.
Philosopher:1 IS THINKING.
Philosopher:4 IS EATING.
Philosopher:4 IS THINKING.
Philosopher:0 IS THINKING.
Philosopher:2 IS EATING.
Philosopher:3 IS EATING.
Philosopher:3 IS THINKING.
Philosopher:1 IS EATING.
Philosopher:1 IS THINKING.
Philosopher:2 IS THINKING.
Philosopher:4 IS EATING.
Philosopher:0 IS EATING.
Philosopher:4 IS THINKING.
Philosopher:1 IS EATING.
Philosopher:1 IS THINKING.
Philosopher:1 IS EATING.
Philosopher:0 IS THINKING.
Philosopher:2 IS EATING.
Philosopher:2 IS THINKING.
Philosopher:1 IS THINKING.
Philosopher:3 IS EATING.
Philosopher:4 IS EATING.
Philosopher:4 IS THINKING.
Philosopher:2 IS EATING.
Philosopher:3 IS THINKING.
Philosopher:1 IS EATING.
Philosopher:2 IS THINKING.
Philosopher:0 IS EATING.
Philosopher:0 IS THINKING.
Philosopher:2 IS EATING.
Philosopher:1 IS THINKING.
Philosopher:3 IS EATING.
Philosopher:2 IS THINKING.
Philosopher:4 IS EATING.
Philosopher:3 IS THINKING.
Philosopher:0 IS EATING.
Philosopher:4 IS THINKING.
Philosopher:1 IS EATING.
Philosopher:1 IS THINKING.
Philosopher:4 IS EATING.
Philosopher:0 IS THINKING.
Philosopher:3 IS EATING.
Philosopher:3 IS THINKING.
Philosopher:0 IS EATING.
Philosopher:4 IS THINKING.
Philosopher:1 IS EATING.
Philosopher:1 IS THINKING.
Philosopher:4 IS EATING.
Philosopher:0 IS THINKING.
Philosopher:3 IS EATING.
Philosopher:3 IS THINKING.
Philosopher:0 IS EATING.
Philosopher:1 IS FINISHED.
Philosopher:4 IS THINKING.
Philosopher:0 IS THINKING.
Philosopher:3 IS EATING.Philosopher:2 IS EATING.
Philosopher:4 IS FINISHED.
Philosopher:2 IS THINKING.
Philosopher:3 IS THINKING.
Philosopher:2 IS EATING.
Philosopher:3 IS FINISHED.
Philosopher:2 IS THINKING.
Philosopher:0 IS EATING.
Philosopher:0 IS THINKING.
Philosopher:2 IS EATING.
Philosopher:0 IS FINISHED.
Philosopher:2 IS THINKING.
Philosopher:2 IS FINISHED.

 

源码下载

创业公司如何招聘优秀工程师

创业公司面对的现实问题是难以招到优秀的工程师。和大公司相比,创业公司的待遇低、压力大、稳定性差,而且既符合职位条件又有创业意愿的人很难寻觅,还需要时机合适,我就遇见过几次候选人因为家事而放弃机会的情况。

现在我每天花1/3的时间在开发工作,1/3的时间在团队事务和沟通,1/3的时间在招揽各种优秀的人才上。

如何找到优质的候选人

在自己的同事和朋友中找。我们团队一位工程师曾经获得招聘达人称号,他本人分享的获胜秘诀是:每天温习通讯录,给新朋旧友推荐机会,平均每天电话量达300个。他号称是专职的猎头、兼职的工程师!

利用在业界的影响力。如果你在业界有一定的影响力和号召力,要好好利用。专业的权威性是最为牢固的领导力。或者试着做一款优秀的应用,进入开发者圈子,你会在里面找到很多合适的候选人。

多认识业界的朋友,让他们帮忙推荐。利用聚会或者人脉认识业界的朋友,让他们帮忙推荐合适的人选。并且经常向他们询问朋友里是否有合适的人选,遇到好的人选是需要时机的,如果你不主动询问他们,重要的信息就可能会错过。参加一些技术沙龙也是很好的选择,多和周围的人交流,他们可能就是你的潜在候选者。

利用新型互联网应用。考虑微博、类似LinkedIn的商务社交网络、类似Quora的SNS问答社区等应用。它们都具有媒体或者社交网络属性,能达到精准和自传播的效果。

如何说服候选人

作为创业团队的领导者,说服力非常重要,这是需要时间和经历来磨炼的。创业能为创业者提供锻炼的机会,能提供大公司所不具备的独特经历,能更大地实现自身价值,能提供更积极向上的工作环境。如果再加上成型的产品、稳定的核心团队、靠谱的商业模式以及对人才的重视态度,是很有可能成功说服对方的。

在说服候选人的过程中,可能会遇到的主要困难包括以下几个方面。

薪酬待遇低。为优秀人才提供适当股权激励是比较合适的手段,另外可以让他们负责重要的产品或业务,许多人很重视这样独当一面的机会。

创业决心不坚决。很多时候候选人的创业决心可能并不坚决。因为我在创业公司和大公司都有过工作经历,所以对各自的优劣和环境都有了解,面对不同的候选人,我可以根据实际情况有针对性地来说服他们。

周围环境影响。候选人可能会遇到一些周围环境的阻力。我在招聘一个优秀工程师加入团队时,正巧遇上他的妻子怀孕,他需要每天早点回家照顾。我立即提出他可以每天提早回家,照顾好妻子后在家工作。

机会众多。优秀的候选人可能同时面临很多机会,所以一定要快速跟进。我曾经在了解一位候选人的背景后,立即联系见面,沟通了解,达成共识,直到最后敲定,所用时间没有超过12小时。

如何留住优秀人才

团队气氛。创业团队的工作很辛苦,要保持快乐的工作状态,团队气氛就一定要积极、平等、开放、向上,不能很压抑。

感情维系。大公司靠文化、中型公司靠制度、小公司靠感情。创业团队必须要靠感情来维系,所以我们经常组织团队活动和拓展来加强成员之间的沟通和了解。

持续激励。一定要给予团队里重要的和做出贡献的人以激励,股权也需要按照多劳多得的原则来进行分配。

统一的理想。我们现在有来自腾讯、微软、百度等大公司的优秀人才,团队非常稳定。因为我们有成熟的产品、众多用户的肯定以及统一的理想,所以大家都愿意齐心协力,一起将共同的事业进行下去。

甄别和吸引优秀人才的加入,这是每个创业团队的领导者永远需要关注的重点话题。

(本文选自《程序员》杂志11年06期,更多精彩内容敬请关注06期杂志)

UI的恶梦

UI可能是编程中最令人头痛的事了。设计UI通常对于程序员来说是一件很痛苦的事情。下面,让我们来看一看一些可怕的UI设计吧,前面几个UI都是出于咱们程序员自己之手,把他们放在这里,希望能引起大家的注意。(国内软件的UI嘛的我就不说了,省得得罪人)下面这个例子不知道你是否让你似曾相识,呵呵,记得我上大学时,用delphi,PB经常开发这样的界面,当时觉得自己特牛!现在看上去嘛,简直就是一个垃圾。(关于UI设计,你可以查看本站的《35个强大的UI设计教程》)

UI的恶梦

首先,我们先来看一个叫wGetGUI的小工具软件,这是一个100%由程序员设计的UI,如下所示:

 

wgetgui-screenshot

看到这样的界面,你会觉得怎么样?“高科技”还是“头晕”?相比起命令行的那个wget,真不知道这个图形界面的工具是怎么被设计出来。哎。这里是这个工具的网页:http://www.jensroesner.de/wgetgui/,网页上还有几张图,也是一样的。

不过,比起下面这个来,wGetGUI算不上什么了。下面这个软件叫做:FileMatrix,这个界面是前所未有的经典,那叫一个相当强大啊。估计可以节省很多对话框和tab页了,把软件的所有功能全部一次性陈列出来。这也是程序员的杰作。(点击图片,你可以慢慢欣赏下面这个UI的细节)

UI

当然,FileMatrix今天还在,其主页在这里。今天的FileMatrix的UI界面已经变得很简洁了,其还支持一些皮肤,不过它们还是很糟糕。如下所示:(更多的图片

marble

让我们再来看看历史上Windows 3.2的某个配色方案:hotdog(如下图所示),真不知道这是谁配的,真是——“红配黄,喜洋洋”啊。

windows-311-hotdog-stand-scheme

不要以为,以简洁著称的Google就没有问题,最近的Google Wave大家用过没有?那个滚动条啊,我实在是没有搞懂为什么设计成那个样子。可谓史上最无厘头的滚动条了。下面,左边是Mac的,右边是Google Wave的,他们俩干的都是一样的事,但Google Wave的太令人摸不着头脑了。

google-wave-scrollbars

对于Google Wave的滚动条,我只想说的是,根据《Don’t make me Think》的原则,这个滚动条和其它例子一样只站在了程序员的角度,而并没有考虑用户体验。下面这些文章,你都可以看看那大家的看法。

  1. http://www.flickr.com/photos/yaili/3990023684/
  2. http://ignorethecode.net/blog/2009/11/15/google_waves_scrollbars/
  3. http://squawk.blogs.starnewsonline.com/10194/is-google-wave-ugly/
  4. http://allentan.posterous.com/google-waves-scrollbar-details
  5. http://technmarketing.com/web/eight-google-wave-annoyances/

你以Google wave scrollbar作为关键词到Google里搜索吧,你可以看到大量的讨论和抱怨。以至于Google自己都要写个说明了。

好了,最后两个图片和设计者无关,设计者在开始的时候可能并没有想到UI能变成这样。下面是关于IE7浏览器的,这张图你可能并不陌生,这是一张当我们的IE被安装了各种工具条后(很多是流氓软件)后的样子。(点击大图细细欣赏)

    iemess2

不要以为Firefox不会像IE一样,那是因为你的Firefox没有装插件,当安装上各种插件后,也是一样的。如下所示(点击图片,慢慢欣赏)。

ffToolbars

最后,让我们看一个现实生活中的UI吧,好像是一个飞机驾驶舱。

Blackhawk-Cockpit

你有什么UI恐怖的经历吗?欢迎与我们分享。

图解SQL的Join

对于SQL的Join,在学习起来可能是比较乱的。我们知道,SQL的Join语法有很多inner的,有outer的,有left的,有时候,对于Select出来的结果集是什么样子有点不是很清楚。Coding Horror上有一篇文章(实在不清楚为什么Coding Horror也被墙)通过 文氏图 Venn diagrams 解释了SQL的Join。我觉得清楚易懂,转过来。

假设我们有两张表。

  • Table A 是左边的表。
  • Table B 是右边的表。

其各有四条记录,其中有两条记录是相同的,如下所示:

id name       id  name
-- ----       --  ----
1  Pirate     1   Rutabaga
2  Monkey     2   Pirate
3  Ninja      3   Darth Vader
4  Spaghetti  4   Ninja

下面让我们来看看不同的Join会产生什么样的结果。

 

				SELECT * FROM TableA
INNER JOIN TableB
ON TableA.name = TableB.name

id  name       id   name
--  ----       --   ----
1   Pirate     2    Pirate
3   Ninja      4    Ninja

Inner join
产生的结果集中,是A和B的交集。

Venn diagram of SQL inner join
				SELECT * FROM TableA
FULL OUTER JOIN TableB
ON TableA.name = TableB.name

id    name       id    name
--    ----       --    ----
1     Pirate     2     Pirate
2     Monkey     null  null
3     Ninja      4     Ninja
4     Spaghetti  null  null
null  null       1     Rutabaga
null  null       3     Darth Vader

Full outer join 产生A和B的并集。但是需要注意的是,对于没有匹配的记录,则会以null做为值。

Venn diagram of SQL cartesian join
				SELECT * FROM TableA
LEFT OUTER JOIN TableB
ON TableA.name = TableB.name

id  name       id    name
--  ----       --    ----
1   Pirate     2     Pirate
2   Monkey     null  null
3   Ninja      4     Ninja
4   Spaghetti  null  null

Left outer join 产生表A的完全集,而B表中匹配的则有值,没有匹配的则以null值取代。

Venn diagram of SQL left join
				SELECT * FROM TableA
LEFT OUTER JOIN TableB
ON TableA.name = TableB.name
WHERE TableB.id IS null

id  name       id     name
--  ----       --     ----
2   Monkey     null   null
4   Spaghetti  null   null

产生在A表中有而在B表中没有的集合。

join-left-outer.png
				SELECT * FROM TableA
FULL OUTER JOIN TableB
ON TableA.name = TableB.name
WHERE TableA.id IS null
OR TableB.id IS null

id    name       id    name
--    ----       --    ----
2     Monkey     null  null
4     Spaghetti  null  null
null  null       1     Rutabaga
null  null       3     Darth Vader

产生A表和B表都没有出现的数据集。

join-outer.png

还需要注册的是我们还有一个是“交差集” cross join, 这种Join没有办法用文式图表示,因为其就是把表A和表B的数据进行一个N*M的组合,即笛卡尔积。表达式如下:

SELECT * FROM TableA
CROSS JOIN TableB

这个笛卡尔乘积会产生 4 x 4 = 16 条记录,一般来说,我们很少用到这个语法。但是我们得小心,如果不是使用嵌套的select语句,一般系统都会产生笛卡尔乘积然再做过滤。这是对于性能来说是非常危险的,尤其是表很大的时候。

(全文完)

程序员需要具备的基本技能

软件开发是一个跨度很大的技术工作,在语言方面,有C,C++,Java,Ruby等等等等,在环境方面,又分嵌入式,桌面系统,企业级,WEB,基础系统,或是科学研究。但是,不管是什么的情况,总是有一些通用的基本职业技能。

这些最基本的职业技能通常决定了一个程序员的级别,能否用好这些技能,直接关系到了程序员的职业生涯。很多程序新手也是因为缺少、达不到或是不熟悉在这些基本技能,所以,他们需要有老手带,需要努力补齐这些技能。而高级程序员应该非常熟悉这些基本技能,而且有能力胜任并带领其他经验不足的程序员。

下面这些基本职业技术可以用来做为对一个程序员的评估,很明显,下面的这些技能都可以用来做面试。虽然,还有很多非技术的因素,但对于评估一个程序员的技术能力来说,其应该是足够的了。

下面是程序员所应该具备的基本职业技能:

 

基本技能 技能描述
阅读代码 这个技能需要程序员能够具备读懂已经存在的代码的能力,这样的能力可以让程序员分析程序的行为,了解程序,这样才能和开发团队一起工作,继承维护或是改进现有的程序。
编写程序 编写程序并不包括程序设计。不要以为编程是一件很简单的事情,很多程序员都认为编程只需要懂得程序语言的语法,并把设计实现就可以了。但是这离编写程序还远远不够,使用什么样的编码风格成为编写程序员最需要具备的基本技能。能否使用非常良好的编程风格直接决写了程序员的级别。
软件设计 这一能力直接决定了需要吏用什么样的代码技术达到怎么样的功能,而系统架构设计直接决定了软件的质量、性能和可维护性。并不是所有的程序在这一方面都非常优秀,但每个程序员都需要或多或少的明白和掌握这一基本技能。
熟悉软件工程 每个程序员都应该明白软件工程是什么东西,都应该知道,需求分析,设计,编码,测试,Release和维护这几个阶段。当然,几乎所有的人都知道这些东西,但并不是每个人都很清楚这些东西。现在很多高级程序员都会混淆“需求规格说明书FS”和“概要设计HLD”。另外,程序员还需要知道一些软件开发的方法论,比如:敏捷开发或瀑布模型。
使用程序库或框架 一个程序员需要学会使用已有的代码,无论是标论的程序库,或是第三方的,还是自己公司内部的,都需要学会做。比如:C++中,需要学会使用STL,MFC,ATL,BOOST,ACE,CPPUNIT等等。使用这些东西,可以让你的工作事半功倍。
程序调试 程序调试是分析BUG和解决问题最直接的能力。没有人能够保证程序写出来不用调试就可以运行正常,也没有人可以保证程序永远不会出BUG。所以,熟练使用调试器是一个程序员需要具备的基本技能。
使用IDE 学会使用IDE工具也会让你的工作事半功倍。比如,VC++,Emacs,Eclipse等等,并要知道这些IDE的长处和短处。
使用版本控制 一定要学会使用版本控制工具,什么叫mainline/trunk,什么叫tag,什么叫branch,怎么做patch,怎么merge代码,怎么reverse,怎么利用版本控制工具维护不同版本的软件。这是程序员需要明的的软件配置管理中最重要的一块。
单元测试 单元测试是每个程序都需要做的。很多单元测试也是需要编码的。一定要学会在xUnit框架下进行单元测试。比如JUnit, NUnit, CppUnit等等。
重构代码 每个程序员都需要有最基本的能力去重构目前已有的代码,使代码达到最优但却不能影响任何的已有的功能。有一本书叫《软件的重构》,每个程序员都应该读一下。
自动化编译 程序员需要使用一个脚本,其能自动化编程所有的工程和代码,这样,整个开发团队可以不停地集成代码,自动化测试,自动化部署,以及使用一些工具进行静态代码分析或是自动化测试。

当然,还有很多的基本技术也是非常重要的,比如,与人的沟通能力,语言的表达能力,写作能力,团队协作能力,适应变化的能力,时间管理能力,多任务处理能力,自我学习能力,故障处理能力,等等,等等,这里只是列举了和技术相关的能力,这些是程序最最最基本的能力,只要是程序员就必需要有的能力。

“21天教你学会C++”

下面是一个《Teach Yourself  C++ in 21 Days》的流程图,请各位程序员同仁认真领会。如果有必要,你可以查看这个图书以作参照:http://www.china-pub.com/27043

看完上面这个图片,我在想,我学习C++有12年了,好像C++也没有学得特别懂,看到STL和泛型,还是很头大。不过,我应该去考虑研究量子物理和生物化学,这样,我才能重返98年杀掉还在大学的我,然后达到21天搞定C++的目标。另外,得要特别提醒刚刚开始学习C++的朋友,第21天的时候,小心被人杀害。呵呵。

当然,上面只是一个恶搞此类图片,学习一门技术,需要你很长的时间,正如图片中的第三图和第四图所示,你需要用十年的时间去不断在尝试,并在错误中总结经验教训,以及在项目开发中通过与别人相互沟通互相学习来历练自己。你才能算得上是真正学会。

这里有篇文章叫《Teach Yourself Programming in Ten Years》,网上有人翻译了一下,不过原文已被更新了,我把网上的译文转载并更新如下:

 

 

用十年来学编程
Peter Norvig

 

为什么每个人都急不可耐?

走进任何一家书店,你会看见《Teach Yourself Java in 7 Days》(7天Java无师自通)的旁边是一长排看不到尽头的类似书籍,它们要教会你Visual Basic、Windows、Internet等等,而只需要几天甚至几小时。我在Amazon.com上进行了如下搜索
 
pubdate: after 1992 and title: days and (title: learn or title: teach yourself)
(出版日期:1992年后 and 书名:天 and (书名:学会 or 书名:无师自通))
 
我一共得到了248个搜索结果。前面的78个是计算机书籍(第79个是《Learn Bengali in 30 days》,30天学会孟加拉语)。我把关键词“days”换成“hours”,得到了非常相似的结果:这次有253本书,头77本是计算机书籍,第78本是《Teach Yourself Grammar and Style in 24 Hours》(24小时学会文法和文体)。头200本书中,有96%是计算机书籍。
 
结论是,要么是人们非常急于学会计算机,要么就是不知道为什么计算机惊人地简单,比任何东西都容易学会。没有一本书是要在几天里教会人们欣赏贝多芬或者量子物理学,甚至怎样给狗打扮。在《How to Design Programs》这本书里说“Bad programming is easy. Idiots can learn it in 21 days, even if they are dummies.” (坏的程序是很容易的,就算他们是笨蛋白痴都可以在21天内学会。)
 
让我们来分析一下像《Learn C++ in Three Days》(3天学会C++)这样的题目到底是什么意思:
  • 学会:在3天时间里,你不够时间写一些有意义的程序,并从它们的失败与成功中学习。你不够时间跟一些有经验的程序员一起工作,你不会知道在C++那样的环境中是什么滋味。简而言之,没有足够的时间让你学到很多东西。所以这些书谈论的只是表面上的精通,而非深入的理解。如Alexander Pope(英国诗人、作家,1688-1744)所言,一知半解是危险的(a little learning is a dangerous thing)
  • C++:在3天时间里你可以学会C++的语法(如果你已经会一门类似的语言),但你无法学到多少如何运用这些语法。简而言之,如果你是,比如说一个Basic程序员,你可以学会用C++语法写出Basic风格的程序,但你学不到C++真正的优点(和缺点)。那关键在哪里?Alan Perlis(ACM第一任主席,图灵奖得主,1922-1990)曾经说过:“如果一门语言不能影响你对编程的想法,那它就不值得去学”。另一种观点是,有时候你不得不学一点C++(更可能是javascript和Flash Flex之类)的皮毛,因为你需要接触现有的工具,用来完成特定的任务。但此时你不是在学习如何编程,你是在学习如何完成任务。
  • 3天:不幸的是,这是不够的,正如下一节所言。

10年学编程

一些研究者(Bloom (1985)Bryan & Harter (1899)Hayes (1989)Simmon & Chase (1973))的研究表明,在许多领域,都需要大约10 年时间才能培养出专业技能,包括国际象棋、作曲、绘画、钢琴、游泳、网球,以及神经心理学和拓扑学的研究。似乎并不存在真正的捷径:即使是莫扎特,他4 岁就显露出音乐天才,在他写出世界级的音乐之前仍然用了超过13年时间。再看另一种音乐类型的披头士,他们似乎是在1964年的Ed Sullivan节目中突然冒头的。但其实他们从1957年就开始表演了,即使他们很早就显示出了巨大的吸引力,他们第一次真正的成功——Sgt. Peppers——也要到1967年才发行。Malcolm Gladwell 研究报告称,把在伯林音乐学院学生一个班的学生按水平分成高中低,然后问他们对音乐练习花了多少工夫:

在这三个小组中的每一个人基本上都是从相同的时间开始练习的(在五岁的时候)。在开始的几年里,每个人都是每周练习2-3个小时。但是在八岁的时候,练习的强度开始显现差异。在这个班中水平最牛的人开始比别人练习得更多——在九岁的时候每周练习6个小时,十二岁的时候,每周8个小时,十四岁的时候每周16个小时,并在成长过程中练习得越来越多,到20岁的时候,其每周练习可超过30个小时。到了20岁,这些优秀者在其生命中练习音乐总共超过 10,000 小时。与之对比,其它人只平均有8,000小时,而未来只能留校当老师的人仅仅是4,000 小时。

所以,这也许需要10,000 小时,并不是十年,但这是一个magic number。Samuel Johnson(英国诗人)认为10 年还是不够的:“任何领域的卓越成就都只能通过一生的努力来获得;稍低一点的代价也换不来。”(Excellence in any department can be attained only by the labor of a lifetime; it is not to be purchased at a lesser price.) 乔叟(Chaucer,英国诗人,1340-1400)也抱怨说:“生命如此短暂,掌握技艺却要如此长久。”(the lyf so short, the craft so long to lerne.)
 
下面是我在编程这个行当里获得成功的处方:
  • 对编程感兴趣,因为乐趣而去编程。确定始终都能保持足够的乐趣,以致你能够将10年时间投入其中。
  • 跟其他程序员交谈;阅读其他程序。这比任何书籍或训练课程都更重要。
  • 编程。最好的学习是从实践中学习。用更加技术性的语言来讲,“个体在特定领域最高水平的表现不是作为长期的经验的结果而自动获得的,但即使是非常富有经验的个体也可以通过刻意的努力而提高其表现水平。”(p. 366),而且“最有效的学习要求为特定个体制定适当难度的任务,有意义的反馈,以及重复及改正错误的机会。”(p. 20-21)《Cognition in Practice: Mind, Mathematics, and Culture in Everyday Life》(在实践中认知:心智、数学和日常生活的文化)是关于这个观点的一本有趣的参考书。
  • 如果你愿意,在大学里花上4年时间(或者再花几年读研究生)。这能让你获得一些工作的入门资格,还能让你对此领域有更深入的理解,但如果你不喜欢进学校,(作出一点牺牲)你在工作中也同样能获得类似的经验。在任何情况下,单从书本上学习都是不够的。“计算机科学的教育不会让任何人成为内行的程序员,正如研究画笔和颜料不会让任何人成为内行的画家”, Eric Raymond,《The New Hacker’s Dictionary》(新黑客字典)的作者如是说。我曾经雇用过的最优秀的程序员之一仅有高中学历;但他创造出了许多伟大的软件(XEmacsMozilla),甚至有讨论他本人的新闻组,而且股票期权让他达到我无法企及的富有程度(译注:指Jamie Zawinski,Xemacs和Netscape的作者)。
  • 跟别的程序员一起完成项目。在一些项目中成为最好的程序员;在其他一些项目中当最差的一个。当你是最好的程序员时,你要测试自己领导项目的能力,并通过你的洞见鼓舞其他人。当你是最差的时候,你学习高手们在做些什么,以及他们不喜欢做什么(因为他们让你帮他们做那些事)。
  • 接手别的程序员完成项目。用心理解别人编写的程序。看看在没有最初的程序员在场的时候理解和修改程序需要些什么。想一想怎样设计你的程序才能让别人接手维护你的程序时更容易一些。
  • 学会至少半打编程语言。包括一门支持类抽象(class abstraction)的语言(如Java或C++),一门支持函数抽象(functional abstraction)的语言(如Lisp或ML),一门支持句法抽象(syntactic abstraction)的语言(如Lisp),一门支持说明性规约(declarative specification)的语言(如Prolog或C++模版),一门支持协程(coroutine)的语言(如Icon或Scheme),以及一门支持并行处理(parallelism)的语言(如Sisal)。
  • 记住在“计算机科学”这个词组里包含“计算机”这个词。了解你的计算机执行一条指令要多长时间,从内存中取一个word要多长时间(包括缓存命中和未命中的情况),从磁盘上读取连续的数据要多长时间,定位到磁盘上的新位置又要多长时间。(答案在这里
  • 尝试参与到一项语言标准化工作中。可以是ANSI C++委员会,也可以是决定自己团队的编码风格到底采用2个空格的缩进还是4个。不论是哪一种,你都可以学到在这门语言中到底人们喜欢些什么,他们有多喜欢,甚至有可能稍微了解为什么他们会有这样的感觉。
  • 拥有尽快从语言标准化工作中抽身的良好判断力。

抱着这些想法,我很怀疑从书上到底能学到多少东西。在我第一个孩子出生前,我读完了所有“怎样……”的书,却仍然感到自己是个茫无头绪的新手。30个月后,我第二个孩子出生的时候,我重新拿起那些书来复习了吗?不。相反,我依靠我自己的经验,结果比专家写的几千页东西更有用更靠得住。

Fred Brooks在他的短文《No Silver Bullets》(没有银弹)中确立了如何发现杰出的软件设计者的三步规划:

  • 尽早系统地识别出最好的设计者群体。
  • 指派一个事业上的导师负责有潜质的对象的发展,小心地帮他保持职业生涯的履历。
  • 让成长中的设计师们有机会互相影响,互相激励。

这实际上是假定了有些人本身就具有成为杰出设计师的必要潜质;要做的只是引导他们前进。Alan Perlis说得更简洁:“每个人都可以被教授如何雕塑;而对米开朗基罗来说,能教给他的倒是怎样能够不去雕塑。杰出的程序员也一样”。

所以尽管去买那些Java书;你很可能会从中找到些用处。但你的生活,或者你作为程序员的真正的专业技术,并不会因此在24小时、24天甚至24个月内发生真正的变化。

(全文完)

BT雷人的程序语言(大全)

还记得以前本站的BT雷人的程序语言吗?除了那几个BrainfuckLOLCODEWhiteSpace,我以为这些是比较BT的语言,但是自从这两天我在网上看到一些(见文章最后的参考一节),我发现我错了,这个世界上,只有更变态,没有最变态。不相,你看看下面这些,简直变态到了极致啊。(下面的语言变态不分排名)

Befunge

第一个变态语言Befunge维基上面说——这门语言由Chris Pressey在1993年创造,本意为设计一种为难编译器的语言……结果马上出现了一批编译器。Befunge的代码是二维的。它用 < > v ^ 这四个符号来控制一个指针在代码中移动,指针经过一个字符或数字则把它压入一个栈,四则运算符号的功能就是弹出栈顶两个元素进行计算后把结果压回去。用 _ 和 | 来表示有条件的方向选择:当栈顶元素为0时向右(上)走,否则向左(下)走。& 和 ~ 分别用于读入数字或字符并压入栈,句号和逗号分别表示将栈顶元素作为整数或字符输出。最后以一个@符号表示程序结束。Befunge代码的注释不需要任何符号标明,你可以把注释写在程序的任何地方,只要运行时指针不会经过它就行了。

下面这段Hello World代码:

>              v
v  ,,,,,"Hello"<
>48*,          v
v,,,,,,"World!"<
>25*,@

下面一个是算圆周率的代码,非常的壮观:

aa*          v                  +------------------------+
vp*9920p*9930<                  | Pi generator in Bef-97 |
>:09a*pa*3/1+19a*p09a*g:09b*v   |                        |
v_@# g*b90 p*b910        < p<   | 7/2/1997, Kevin Vigor  |
>19a*g:+1-29b*p19a*g::09v       +------------------------+
v*a90g*b90*g*b91: _v#p*9<
>g-#v_ 2a*+$  v  :$
>1-aa*ga*+v  p
v1:/g*b92p*991:<  *
>9b*p29b*g*199*gv9
v*b92p*aa-1g*990-<9
>g2-29b*p099*g1-:0^
v -9p*b92:%ag*991  <
>#v_ 299*g1+299*p>       ^
>09b*g:#v_$v
v93p*b90-1<
>9*g199*ga/+.v
v:g*992 <p*9 92-<
v_29b*g399*p ^
>09b*g:#v_v      1
vp*b90-1    < $      g
>199*g9`#v_'9,v      *
>'0, >' ,299^

通常认为Befunge是第一个基于“二维控制流”的语言,后来衍生出的一大批类似的语言都是受的Befunge影响。例如PingPong语言就是把Befunge的四种箭头符号换成正反斜杠,控制指针移动方向90度旋转,起一个反弹的作用。

Chef

Chef如其名一样“主厨”(Wiki link),这门语言主要是为了让程序代码看起来像菜谱。这可以使得我们的程序员更像是大厨了,呵呵。该语言于2002年由David Morgan-Mar推出,核心是栈操作,特征就是——一套完整的Chef代码就是一个菜谱,程序名就是菜名,变量声明就是罗列原材料,后面一系列栈操作,就是菜肴的制作方法。把程序编写比作调和鼎鼐,有点意思,家庭主妇(或者“准家庭主妇”)试试看,权且当作人生预习。

用Chef编写Hello World代码如下:(在其网站上还有一个斐波拉契数的例子

Hello World Souffle.

Ingredients.
72 g haricot beans
101 eggs
108 g lard
111 cups oil
32 zucchinis
119 ml water
114 g red salmon
100 g dijon mustard
33 potatoes

Method.
Put potatoes into the mixing bowl.
Put dijon mustard into the mixing bowl.
Put lard into the mixing bowl.
Put red salmon into the mixing bowl.
Put oil into the mixing bowl.
Put water into the mixing bowl.
Put zucchinis into the mixing bowl.
Put oil into the mixing bowl.
Put lard into the mixing bowl.
Put lard into the mixing bowl.
Put eggs into the mixing bowl.
Put haricot beans into the mixing bowl.
Liquefy contents of the mixing bowl.
Pour contents of the mixing bowl into the baking dish.

Serves 1.

代码解读——原材料名显然可以随便改成别的原料,哪怕用单个字母也可以,不过少了点趣味性,但原料前面代表数量的数字不能改,那是ASCII代码。接下来菜肴制作方法就是把一个个字母和符号(都是ASCII)压入栈(就是代码中的“Put XXX into the mixing bowl”,从最后一个感叹号开始压),最后再把你做的菜托出上桌。

顺便说下,David Morgan-Mar已经设计出8种非主流编程语言了,还有一个变态的操作系统Petrovich。  参看这位大哥的——DM’s Esoteric Programming Languages(下面会介绍这位老大搞出来的语言)

Shakespeare

Shakespeare语言正如其名,其要让你的程序像“莎士比亚”的剧本一样充满艺术气息。

这个语言于2001年由Karl Hasselstrom和Jon Aslund联合推出,Shakespeare的代码完全模仿莎士比亚的戏剧。它也是一个基于栈的程序语言,程序中出场的每一个人物都代表一个栈。Shakespeare的代码自由度很高,因此同一个程序你可以写出完全不同的代码出来。

Shakespeare的Hello World代码如下(就是一部比较完整的“罗密欧与朱丽叶”的戏剧,作好心理准备)。“剧本”内容很无聊,就是一帮人在莫名其妙地称赞某些东西,里头还有古英语词汇,莎翁要是见了,可能会吐血。这里面Hello World或其ASCII码体现在全剧时不时出现的“The difference between……”句里面,根据各指代物品的好坏(比如鲜花算好的,牛粪算坏的)代表各数字,再进行各种运算最后相减(“The difference”暗指减法),得出一个字母或符号的ASCII码表。发明这个语言的人真是BT啊。

Romeo, a young man with a remarkable patience.
Juliet, a likewise young woman of remarkable grace.
Ophelia, a remarkable woman much in dispute with Hamlet.
Hamlet, the flatterer of Andersen Insulting A/S.
Act I: Hamlet's insults and flattery.
Scene I: The insulting of Romeo.
[Enter Hamlet and Romeo]
Hamlet:
You lying stupid fatherless big smelly half-witted coward!
You are as stupid as the difference between a handsome rich brave hero and thyself! Speak your mind!
You are as brave as the sum of your fat little stuffed misused dusty old rotten codpiece and a beautiful fair warm peaceful sunny summer's day. You are as healthy as the difference between the sum of the sweetest reddest rose and my father and yourself! Speak your mind!
You are as cowardly as the sum of yourself and the difference between a big mighty proud kingdom and a horse. Speak your mind.
Speak your mind!
[Exit Romeo]
Scene II: The praising of Juliet.
[Enter Juliet]
Hamlet:
Thou art as sweet as the sum of the sum of Romeo and his horse and his black cat! Speak thy mind!
[Exit Juliet]
Scene III: The praising of Ophelia.
[Enter Ophelia]
Hamlet:
Thou art as lovely as the product of a large rural town and my amazing bottomless embroidered purse. Speak thy mind!
Thou art as loving as the product of the bluest clearest sweetest sky and the sum of a squirrel and a white horse. Thou art as beautiful as the difference between Juliet and thyself. Speak thy mind!
[Exeunt Ophelia and Hamlet]
Act II: Behind Hamlet's back.
Scene I: Romeo and Juliet's conversation.
[Enter Romeo and Juliet]
Romeo:
Speak your mind. You are as worried as the sum of yourself and the difference between my small smooth hamster and my nose. Speak your mind!
Juliet:
Speak YOUR mind! You are as bad as Hamlet! You are as small as the difference between the square of the difference between my little pony and your big hairy hound and the cube of your sorry little codpiece. Speak your mind!
[Exit Romeo]
Scene II: Juliet and Ophelia's conversation.
[Enter Ophelia]
Juliet:
Thou art as good as the quotient between Romeo and the sum of a small furry animal and a leech. Speak your mind!
Ophelia:
Thou art as disgusting as the quotient between Romeo and twice the difference between a mistletoe and an oozing infected blister! Speak your mind!
[Exeunt]

BIT

BIT语言也是 David Morgan-Mar 搞出来的。程序员在拥有访问所有数据的全部权限。这是一款强大的编程工具。在高级程序语言中,该工具可以操作这些令人费解的数据。

看看下面这段代码,其展示了BIT的强大之处——代码和注释的完美统一。(很像BASIC)

LINE NUMBER ONE CODE READ GOTO ONE ZERO
LINE NUMBER ONE ZERO CODE VARIABLE ZERO EQUALS THE JUMP REGISTER GOTO ONE ONE
LINE NUMBER ONE ONE CODE READ GOTO ONE ZERO ZERO
LINE NUMBER ONE ZERO ZERO CODE VARIABLE ONE EQUALS THE JUMP REGISTER GOTO ONE ZERO ONE
LINE NUMBER ONE ZERO ONE CODE THE JUMP REGISTER EQUALS OPEN PARENTHESIS VARIABLE ZERO NAND VARIABLE ONE CLOSE PARENTHESIS NAND OPEN PARENTHESIS VARIABLE ZERO NAND VARIABLE ONE CLOSE PARENTHESIS GOTO ONE ONE ZERO IF THE JUMP REGISTER IS EQUAL TO ONE GOTO ONE ZERO ZERO ZERO IF THE JUMP REGISTER IS EQUAL TO ZERO
LINE NUMBER ONE ONE ZERO CODE PRINT ONE GOTO ONE ONE ONE
LINE NUMBER ONE ONE ONE CODE PRINT ZERO
LINE NUMBER ONE ZERO ZERO ZERO CODE THE JUMP REGISTER EQUALS OPEN PARENTHESIS VARIABLE ZERO NAND VARIABLE ZERO CLOSE PARENTHESIS NAND OPEN PARENTHESIS VARIABLE ONE NAND VARIABLE ONE CLOSE PARENTHESIS GOTO ONE ZERO ZERO ONE IF THE JUMP REGISTER IS EQUAL TO ZERO GOTO ONE ZERO ONE ZERO IF THE JUMP REGISTER IS EQUAL TO ONE
LINE NUMBER ONE ZERO ZERO ONE CODE PRINT ZERO
LINE NUMBER ONE ZERO ONE ZERO CODE PRINT ONE

当然,对于空格和换行符,显得太冗余了,去掉他们也没有问题。

LINENUMBERONECODEREADGOTOONEZEROLINENUMBERONEZEROCODEVARIABLEZEROEQUALSTHEJUMPR
EGISTERGOTOONEONELINENUMBERONEONECODEREADGOTOONEZEROZEROLINENUMBERONEZEROZEROCO
DEVARIABLEONEEQUALSTHEJUMPREGISTERGOTOONEZEROONELINENUMBERONEZEROONECODETHEJUMP
REGISTEREQUALSOPENPARENTHESISVARIABLEZERONANDVARIABLEONECLOSEPARENTHESISNANDOPE
NPARENTHESISVARIABLEZERONANDVARIABLEONECLOSEPARENTHESISGOTOONEONEZEROIFTHEJUMPR
EGISTERISEQUALTOONEGOTOONEZEROZEROZEROIFTHEJUMPREGISTERISEQUALTOZEROLINENUMBERO
NEONEZEROCODEPRINTONEGOTOONEONEONELINENUMBERONEONEONECODEPRINTZEROLINENUMBERONE
ZEROZEROZEROCODETHEJUMPREGISTEREQUALSOPENPARENTHESISVARIABLEZERONANDVARIABLEZER
OCLOSEPARENTHESISNANDOPENPARENTHESISVARIABLEONENANDVARIABLEONECLOSEPARENTHESISG
OTOONEZEROZEROONEIFTHEJUMPREGISTERISEQUALTOZEROGOTOONEZEROONEZEROIFTHEJUMPREGIS
TERISEQUALTOONELINENUMBERONEZEROZEROONECODEPRINTZEROLINENUMBERONEZEROONEZEROCOD
EPRINTONE

Haifu

Haifu程序语言也是David Morgan-Mar 搞出来的。从命名上就可以看出来它是一个汉语拼音。正是如此,作者想使用东方的哲学来创造一种编程的语言。其中还有Yin(阴)和 Yang(阳)——相当于布尔变量中的True/False,当然,也有金(Metal)木(Wood)水(Water)火(Fire)土(Earth)。呵呵。

  • Wood: tree, grass, cherry, oak.
  • Fire: flame, ash, smoke, embers.
  • Earth: soil, mountain, rock, plain.
  • Metal: sword, iron, plough, knife.
  • Water: rain, snow, river, ice.

自然出现了一张关系表:

 

元素关系 操作
B 生A A+B
B 克 A A-B
B 怕 A A/B
B 爱 A A*B
B 就是 A 如果A和B都是阳,则是阳,否则是阴

Piet

David Morgan-Mar 发明的用位图编程的Piet语言也是BT到了极致,你还记得前两的那个“我的hello world编不过去”文章中的那个强人用windows的画图程序编程的例子吗?呵呵Piet完全是用位图编程的语言。

下面这个图片就是其Hello World的示例:

再看看斐波拉契数列的程序示例:

这里还有更多的示例:http://www.dangermouse.net/esoteric/piet/samples.html

Malbolge

Malbolge语言,是最早的一个以代码丑陋为目标而设计出的程序语言,你几乎不可能读懂Malbolge的代码。它共有8条指令,所有运算都基于3进制,控制程序流的唯一指令是无条件跳转。其是BenOlmstead在1998年引进公共领域的深奥程序语言,名称来源于“the eighth circle of hell in Dante’s Inferno”,之后更名为Malbolge。

这被认为是地狱级的编程语言。

看看它的Hello World程序:

('&%:9]!~}|z2Vxwv-,POqponl$Hjig%eB@@>}=<M:9wv6WsU2T|nm-,jcL(I&%$#"
 `CB]V?Tx<uVtT`Rpo3NlF.Jh++FdbCBA@?]!~|4XzyTT43Qsqq(Lnmkj"Fhg${z@>

Unlambda

关于Unlambda语言,David Madore是这个语言的发明人,他于1976年8月3日生于法国,其是法国-加拿大籍数学家和计算机科学爱好者)。在unlambda里,所有东西都是函数。基本操作就是S, K, 和I三个组合子。当然,unlambda也加入一些扩展,让程序稍微好些一点。

```s``sii`ki
 ``s``s`ks
     ``s``s`ks``s`k`s`kr
               ``s`k`si``s`k`s`k
                               `d````````````.H.e.l.l.o.,. .w.o.r.l.d.!
                        k
      k
  `k``s``s`ksk`k.*

Ook!

Ook! 语言也是David Morgan-Mar 发明的,与Brainfuck类似, 但用单词“Ook!”,“Ook.” 和“Ook?”代替。我们来看一个Hello World的一个示例:

Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook! Ook? Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook! Ook! Ook? Ook! Ook? Ook.
Ook! Ook. Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook! Ook? Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook?
Ook! Ook! Ook? Ook! Ook? Ook. Ook. Ook. Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook. Ook! Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook! Ook. Ook. Ook? Ook. Ook? Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook? Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook? Ook! Ook! Ook? Ook! Ook? Ook. Ook! Ook.
Ook. Ook? Ook. Ook? Ook. Ook? Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook! Ook? Ook? Ook. Ook. Ook.
Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook. Ook? Ook! Ook! Ook? Ook! Ook? Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook.
Ook? Ook. Ook? Ook. Ook? Ook. Ook? Ook. Ook! Ook. Ook. Ook. Ook. Ook. Ook. Ook.
Ook! Ook. Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook.
Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook! Ook!
Ook! Ook. Ook. Ook? Ook. Ook? Ook. Ook. Ook! Ook.

下面是一些转换器和解释器:

TMMLPTEALPAITAFNFAL

你没看错,上面这一排毫无意义的字母是一个语言的名称。它是The Multi-Million Language Project To End All Language Projects And Isn’t That A Fine Name For A Language的缩写。TMMLPTEALPAITAFNFAL语言没有固定的语法规则,每一天都是不同的语法。例如,2000年10月13日你可以使用DIV但不能使用MOD;到了10月14日时你可以使用MOD了但DIV又不能用了。因此,你今天写的程序运行起来完全正常,但是到了明天就无法编译了。下面是一个TMMLPTEALPAITAFNFAL的Hello World程序,当然现在已经无法编译了。

DECLARE CELL 100 AS READPOS
 DECLARE 10 AS NEWLINE
 WRITE CHAR NEWLINE
 COPY "Hello, World" TO CELL 0
 COPY 0 TO READPOS
 WHILE READPOS INDIRECT DO GOSUB 300
 WRITE CHAR NEWLINE
 RETURN
LINE 300: WRITE CHAR READPOS INDIRECT
 ADD 1 TO READPOS
 RETURN

INTERCAL

INTERCAL语言Wikipedia)全称是“Compiler Language With No Pronounceable Acronym”。自认为是“超级黑客”的人可以试试用这个语言写程序。由老牌黑客Don Woods 和 James M. Lyon 在1972年发明,其是用来讽刺当时的那些编程语言。今天 这个语言有两个版本,一个是由牛人Eric S. Raymond维护的C-INTERCAL,另一个是Claudio Calvelli 维护的CLC-INTERCAL。(:在自由软件启蒙阶段,Eric S. Raymond以如椽之笔呼啸而出,其核心著作被业界成为”五部曲”:《黑客道简史》(A Brief History of Hackerdom)、 《大教堂和市集》(The Cathedral and the Bazaar)、《如何成为一名黑客》(How To Become A Hacker)、《开拓智域》(Homesteading the Noosphere)、《魔法大锅炉》(The Magic Cauldron)。其中最著名的当然还是《大教堂和市集》,它在自由软件运动中的地位相当于基督教的《圣经》。而用黑客们的话说,这是”黑客藏经阁”的 第一个收藏。)

来看看其Hello World的程序:

DO ,1 <- #13
PLEASE DO ,1 SUB #1 <- #238
DO ,1 SUB #2 <- #108
DO ,1 SUB #3 <- #112
DO ,1 SUB #4 <- #0
DO ,1 SUB #5 <- #64
DO ,1 SUB #6 <- #194
DO ,1 SUB #7 <- #48
PLEASE DO ,1 SUB #8 <- #22
DO ,1 SUB #9 <- #248
DO ,1 SUB #10 <- #168
DO ,1 SUB #11 <- #24
DO ,1 SUB #12 <- #16
DO ,1 SUB #13 <- #162
PLEASE READ OUT ,1
PLEASE GIVE UP

HQ9++

HQ9++语言同样是David Morgan-Mar 发明的,其带有四个指令的joke语言。

PerlYuYan

PerlYuYan语言是一个能令人使用中文文言文开发程式 Perl 程式的 Perl 模块,由唐凤于2002年一月发表。它是中文编程语言的尝试。作者利用中文的特质,将许多指令改成以一个中国汉字来表示,因而造成了文言语法的感觉。

看看下面的这段代码,相当的文言文啊。有兴趣可以去CPAN上下载回来玩玩。

#!/usr/local/bin/perl

use Lingua::Sinica::PerlYuYan;

用警兮用嚴。

印道
一至一
哉兮

印編曰雜申雜申矣
  又纖曰龍鼠矣
    又曰一矣

亂曰
國無人莫我知兮    又何懷乎故都
既莫足與為美政兮  吾將從彭咸之所居

还有下面这个五言。

# The Sieve of Eratosthenes - 埃拉托斯芬篩法
use Lingua::Sinica::PerlYuYan;

  用籌兮用嚴。井涸兮無礙
。印曰最高矣  又道數然哉。
。截起吾純風  賦小入大合。
。習予吾陣地  並二至純風。
。當起段賦取  加陣地合始。
。陣地賦篩始  繫繫此雜段。
。終陣地兮印  正道次標哉。
。輸空接段點  列終註泰來。

参考:

看过这些,我我还有什么好说的呢,什么C/C++/Java,神马都是浮云了……

(全文完)

哪本书是每个程序员都该阅读的?

本文是从 What is the single most influential book every programmer should read? 这篇文章翻译而来。

国外知名网站stackoverflow上有一个问题调查: 哪本书是对程序员最有影响、每个程序员都该阅读的书?, 这个调查已历时两年,目前为止吸引了153,432人访问,读者共推荐出了478本书(还在增加),其中最火的一本书《Code Complete》被顶了1306次。如果你是个程序员,你一定有兴趣看看这些书里你都看过几本,如果你一本没看过的话,我也不好说什么,也许你是个天 才,但我相信大多数人都知道,你在学校里根本学不到什么真正的工作中需要的知识,我们毕业后能帮助我们在公司中胜任工作的老师就是这些优秀的书籍,一本好 书可以改变一个人的一生。

下面是这个调查中排名靠前的书的一个简单的清单:

第一名:1306票《Code Complete (2nd Ed) by Steve McConnell》,中文版《代码大全(第二版)》,两届Software Jolt Award震撼大奖得主!

cover

 

第二名:1161票 《The Pragmatic Programmer》,中文版《程序员修炼之道》

The Pragmatic Programmer

 

第三名:689票 《Structure and Interpretation of Computer Programs》,中文版《计算机程序的构造和解释》

Structure and Interpretation of Computer Programs - 2nd Edition (MIT Electrical Engineering and Computer Science)

 

第四名:557票 《The C Programming Language》,中文版《C程序设计语言》

The C Programming Language Book

 

第五名:472票 《Refactoring: Improving the Design of Existing Code》,中文版《重构:改善既有代码的设计》

Refactoring: Improving the Design of Existing Code

 

第六名:472票 《Introduction to algorithms》,中文版《算法导论》

Introduction to algorithms cover image

 

第七名:430票 《The Mythical Man-Month》,中文版《人月神话》

The Mythical Man-Month: Essays on Software Engineering, Anniversary Edition (2nd Edition)

 

第八名:426票 《Design Patterns》,中文版《设计模式》

 

第九名:386票 《The Art of Computer Programming(First Volume Hardcover)》,中文版《计算机程序设计艺术第 (第一卷)》

http://www.aqee.net/wordpress/wp-content/uploads/2011/03/75dd9_programming_41T1XCAEE1L.jpg

 

第10名:353票 《Compilers: Principles, Techniques, and Tools 》,中文版《编译原理》

Compilers: Principles, Techniques, and Tools (2nd Edition)

 

第11名:329票 《Head-First Design Patterns》,中文版《Head First 设计模式》

 

当然了,这里的排名并不具有什么权威性,但绝对可以说都是好书,这11本外还有很多书虽然票数不是那么多,但大家估计都耳熟能详,比如 《Effective C++》(中文版《Effective C++:改善程序与设计的55个具体做法》),《Clean Code》(中文版《代码整洁之道》),《Effective Java》(中文版《Effective Java中文版(第2版)》等 。

记得有位先哲曾说过:一种编程语言的重要性并不在于语言本身,而是在于这种语言来体现出来的编程思维模式。所以说,并不是你用到的书才去读,读书是一种习惯。