2012年3月9日星期五

踏术而上

对于技术人员来说,学习是必须的。有不少人.NET的同学都是沿着提问(CSDN)->博客(博客园)这条道路学习的,但有一天你可能会遇到瓶颈:为什么感觉掌握了不少东西,但具体到开发或者工作的时候,总是觉得不能得心应手,总是不知道从何开始施展,又或者总是觉得做出来的东西是不太对劲呢?

如果你有这样的体会,也许可以听听我不见得正确的看法。我认为这基本上属于国内教育方式的遗毒。国内教育方式总爱填鸭式,比拼谁记得的东西多,很少引导和启发每个个体去独立的思考问题。这种方式所教育出来的同学,对于解决封闭问题都能得心应手,但面对开放性问题就会无从下手。

最近我遇到的例子是这样的,说:系统突然从某天开始,每天都出现各种卡、慢、错的情况。这个问题我一开始并没有介入,而是试图让下面的人自行尝试面对,最后发现结果不理想。处理的方式基本上停留在听说别的部门告知机房正遭受攻击,然后就反馈给用户说机房受到攻击,全然不管攻击是否真的影响到我们,或者是否真的是因为这样导致我们系统的不稳定。

在提醒了问题可能不是这样之后,处理的方式又转为随机式的试错,比如尝试机房流量转移,甚至提出建议说是否可以增加前段服务器。但当我仔细去了解之后发现,基本上没有任何调查,也就没有任何证据能表明这是前段服务器的问题,更无法证明增加了前段服务器就能解决问题。于是,我说明了先找证据再分析的重要性,并明确不要在假设的基础上做推理。比如有如下推理:加入HaProxy都扛不住了,那么后端早就扛不住了,现在后端没看到报警,所以前端一定没有问题。理论上这应该是正确的,但实际上HaProxy因为配置给后端服务的并发连接数量很小,导致大量连接过来的时候HaProxy认为后端已经没有服务器有能力进行处理,于是报告了503错误。

在此之后,还有同学抱怨没有给出解决方案,所以不知道怎么做。其实,如果你想坐比较高的位置,那么你必须拥有“独立思考解决从未遇到过的问题”的能力,也就是解决开放性问题的能力。也许有人会说:我不会Linux啊,总得有人来带一下吧。我必须说明,除了给你几个建议,告诉你要自己想之外,剩下事情别人帮不了你。如果你希望通过别人手把手教你处理几次问题来获得成长,那我可以说你不过获得了一些经验值,下次出现全新的问题时,你依旧是小白一只。

这种处理开放性问题的诀窍,在于思考关键点并动手检验这一步骤,而不是学习使用某种工具。很多人喜欢问一些关于语言、设计模式、算法、HaProxy的配置方法等等的问题,这些知识是必须要具备的。前述的那些名词,是一些工具,或者说是“道法术器”当中的“器”。不学无术的意思,就是你不学习就不知道有关如何使用该工具的只是。如果你随便大概的糊弄一下,断然是不行的。但同时你也需要清醒的认识到,这样的知识再多,也摆脱不了蓝领的定位。要想进步,成为高人、神级的人,你需要“懂法”、“得道”。

术,是指具体的操作办法。以武术为例,拳法套路可以说是术,并不能实战,真正实战的时候并不是按套路来的。而张无忌学习太极之后“全都忘了”,就是得道了。而对于码农来说,术就是如何在工作当中熟练使用设计模式。请注意,是熟练而不是正确。我经常遇到的一个典型是滥用,或者说是不知道何时要用,为何要用,这是因为使用者并没有去思考背后的道法。

比如说做一个很简单的工具:这个工具会自动监控IIS进程,如果发现长时间CPU很高,就会调用一个程序来重启相应的进程池。重启的过程包括三个步骤:1、执行一个命令找到PID对应的进程池;2、执行重启进程池命令;3、根据命令执行的结果记录日志。由于步骤2可能会比较耗时,甚至可能因不明原因死机。考虑到持续监测的需要,异步执行是很必要的。有人会大致设计成:

ManualResetEvent exitEvent = new ManualResetEvent(false);
void Restart(int w3pProcessId)
{
   string poolName = GetPoolName(w3pProcessId);
   Task task = new Task(RunRestartCommand, poolName);
   task.Start();
   if (exitEvent.Wait(10000))
   {
      LogTimeout(poolName, w3pProcessId);
   }
   else
   {
      LogSuccess(poolName, w3pProcessId);
   }
}

// 其它函数省略

你看,多豪华啊:通过Task来实现异步,内部通过ManualResetEvent放出信号让外部继续执行后续操作,同时通过Wait(timeout)来保证不会死机。这里每一个“术”都看着很眼花缭乱,但从简单就是美这个“道”来说,并不优美。比如可以这么写:

void Restart(int w3pProcessId)
{
   string poolName = GetPoolName(w3pProcessId);
   Process restartCommandProcess = CreateAndRunProcess(poolName);
   if (restartCommandProcess.WaitForExit(10000))
   {
      LogTimeout(poolName, w3pProcessId);
   }
   else
   {
      LogSuccess(poolName, w3pProcessId);
   }
}

通过建立一个Thread来调用上述函数,是否显得更简单呢?实际上第一个例子还有另一个错误:实际上Restart函数还是阻塞性的,只不过控制在10秒以内,对于持续监控而言,仍然是不稳定的因素。

回过头来讲,Task虽说是异步的一种,但并非用于解决这类的问题的。Task实际上是为了让各个异步步骤能够更方便的串起来,包括各种取消功能。用在这里,显然是“好钢没用在刀刃上”,或者说是错误的。

当你学习完术之后,一定要思考背后的道法,或者说“为什么”。否则,你就很容易像第一个例子中那样,堆砌各种花拳绣腿。术完全可以学,而道法则需要会悟。对于现成的案例,自然也可以说出些道理法则。但是越到高处,你会发现有越来越多的未知问题,同时已经遇到并且成功解决的人会越来越少。换句话说,有大量的问题是不可能有说明书告诉你背后的门道。和“器”之“术”不一样,后者发明“器”的人,必然会提供“术”。比如推出Squid的团队,会给你一个说明书。定义“设计模式”的人,也会告诉你这是什么,怎么用。但只有当你可以发现并理解背后的问题和道理,你才可能发明Squid,发现设计模式的时候。

为什么到了看写博客这个阶段之后,通常会有一个瓶颈?那是因为大多数人并没有明白上面的奥妙,仍然在弄术。关于这一点,看看博客园的文章便可知一二。比如摘抄标题如下:

ASP.NET伪静态 UrlRewrite(Url重写) 实现和配置

这类的文章在博客园中占比当是大头,基本没有什么道法。少量的如敏捷立会两三事,标题算是“法”的范畴,但内容却只有问题和结论,没有中间思考过程。真正讲解道法的文章,少之又少。如果认同,却又不知如何提升,那就需要做下面两件事情:
1、寻找一些讲道理法则的博客,比如

2 条评论:

  1. 正在沿着CSDN到博客园的道路学习,还没到瓶颈期~~~哈哈

    回复删除
    回复
    1. 头一个沙发哦~话说挺冷清的,但这样倒是可以沉下来自我清净一下。

      删除