Author: qingbo

  • 粗读了 Web 信息架构

    前段时间买了一本“Web 信息架构”,英文名是 Information Architecture for the World Wide Web – Designing Large-Scale Web Sites. 网上还是有一些好评的,不过我却感觉有点无聊。

    我这人本来就不是特别喜欢读书,遇到这种比较无聊的就更觉得没劲了。我只认真地看了一小半,然后用刚才的十几分钟粗略浏览了剩余的内容。这本书给我的感觉就是总结了一些 common sense,或者说是汇编了所谓信息架构所涉及到的一些学科的知识。

    我很难想象这样一个会干涉到产品用户体验、数据库设计等的角色如何在公司的夹缝中生存,看来目前专注于这个的话,也只能给别人做咨询了。不过,产品设计人员在无聊的时候可以打发一下时间。

    书中提到的“搜索日志分析”我还是有点兴趣的,该书在109页的脚注里推荐了一本书 “Search Analysis for Your Site: Conversations with Your Customers”,2007年出版。但是我在网上搜寻许久都没找到,到脚注给出的链接看,发现该书名字跟脚注有些出入,并且状态是 “in progress” ——并没有出版。该未出版的书和这本信息架构的作者中都有 Louis Rosenfeld 这个人,我不知道他们出于什么目的以这样的方式利用这个广告位。我很害怕这本书也是由废话堆积而成。

    该书引用的一段话我倒是很喜欢(115页):

    等一下,葛瑞蒂,月亮还没升上来。

    等到月亮升上来,才能看见我洒的面包屑。

    面包屑会告诉我们回家的路。

    ——《韩森与葛瑞蒂》

    这就是“面包屑”导航 (breadcrumb navigation)名字的由来。我没有找到完全对应的英文原文,但是这一段很相似:

    “Wait, when the moon comes up I will be able to see the crumbs of bread that I scattered, and they will show us the way back home.”

  • .NET 还是 Java?

    今天跟一个计算机专业上大二的小兄弟聊了一会,期间他问:”你们公司招 Java 程序员?是不是基本大公司都不用 .NET?“

    他在自学 C#,这让我隐约回想起我学习计算机的过程。我基本是上大学才开始接触计算机,之前也就去过几次网吧,去校长办公室里打过几次抢滩登陆战。大学的一个寒假,我带回家一大堆计算机方面的书要自学,印象比较深的是还有一本讲 3ds Max 的书,当时什么都不知道,什么都想学……但是当时没有任何人给我指路,一直感觉很迷茫。就像这位小兄弟一样,经常担心,我学了这个技术将来有没有饭吃?

    其实大学跟培训学校的区别就是,培训学校主要传授你一门吃饭的技艺,而大学要教会你如何自己探索吃饭的本事。很不幸的是许多大学已经沦落成为培训学校了。上完大学之后别人问你在大学学到了什么,你如果说我学会了 Java 或者学会了 .NET,岂不让人耻笑?如果大学的目的就在于此,那么大学早就应该开设 Java 系、.NET 系了,学制最多一年。

    问这样的问题,就像要去种地,问别人我是该学锄头呢?还是该学犁呢?好吧,你学犁吧,你就永远是一头牛。你只管闷头拖着犁往前走,撒下的是别人的种子,结出的是别人的果实。

    对于计算机系的人来说,数据结构、算法、编译原理、操作系统原理、计算机体系结构等这些还是必须要学好的。Java 也好,.NET 也好,编程语言只是工具。打好了基础,学什么语言都很容易,可以融会贯通,可以用它们来实现自己的想法。否则,就很容易沦为可怜的流水线工人,帮别人实现那可恶的 CMM…

  • 物流也有技术含量

    今天又看到了一篇分析物流的文章 – “亚马逊“乱”改卓越”,我感觉写得还是挺不错的。想起来几个月前看到的类似主题的文章“为什么都要自建物流”,该文对自建物流的好处也分析得很详细。再到网上搜“自建物流”,发现漫山遍野都是这个话题。

    如果我没记错的话,我只在当当网买过一本书(当当买书经历),恰好就遭遇了一次不愉快,此后就尽量避免在当当买书了。每次都是在豆瓣、当当看书评,然后到卓越下单买书。

    说实话,卓越的网站做得挺烂的,但是吸引我的就是它的物流。买的东西能够准确及时地送达,这才是最重要的。自建物流毫无疑问可以更好地跟自己的电子商务系统对接,提供更好更便捷的送货服务,展现更好的品牌形象。

    物流方面我肯定是外行,不敢多说免得遭人耻笑。不过做互联网多多少少也跟电子商务有点关系,而上面提到的都是电子商务网站的物流。我很欣喜的看到,物流也可以很有技术含量。

    看到用户行为分析在物流系统决策中的应用,感觉数据分析、数据挖掘还是大有前途的,尤其是在中国,大部分的企业这一块还是空白,但是大家都开始认识到它的重要性了。

  • 第二次滑雪

    去年春天我平生第一次去滑雪,没有经过人指导,头回上道之后都不知道怎么下来。不过后来知道点基本的东西了,看看下面人少的时候就冲下去了……

    前天公司组织大家一起去滑雪泡温泉,还很贴心地找教练教我们,总算知道了一些要领,在初级道上可以很自如地滑了。后来上了两次中级道,不过那段又陡又窄的路很让我发怵,速度一快了就忘记怎么控制了。但是再回来初级道,就感觉速度太慢,想快都快不起来。最后我忽悠部门所有同事包括第一次来滑雪的也都上中级道玩了一把……

    比较好的是我在中级道上虽然有时候歪歪斜斜,但最终没有倒,整天下来一个跟头都没摔。

    晚上抽奖还抽到了一瓶 Johnnie Walker, 立即就贡献出来给大家过了酒瘾。有同事后来甚至喝得不省人事。总体来说这次玩得挺愉快的,只是我们在温都水城住,却没有机会去水世界玩点刺激的项目。

  • 不能取得类 WorkBook 的 SaveAs 属性

    同事(非编程出身)用 Ruby 写了个程序,生成一个 Excel 文件,把它作为附件发邮件给某些人。Excel 文件中是昨日数据的报告,他让我帮他每天让该程序自动运行一次。因为程序生成 Excel 文件调用的是 win32 OLE,所以是不能在 Linux 里用 cron 定期运行的,只好在一台 Windows 机器上用“任务计划程序”来实现。

    奇怪的是到了预定的时间,我们并没有收到电子邮件。到任务计划程序中看,果然任务执行失败了,但是没有更详细的信息,这符合微软的风格──用户不需要知道太多。于是在程序中加入 exception handling,将异常信息写入文件,执行任务后,看到异常是:

    OLE error 0x800a03ec: 不能取得类 WorkBook 的 SaveAs 属性

    得说明一下,这个 Ruby 程序如果是双击或者在命令行执行,会正常运行。因为指定了 DisplayAlerts = false, 保存文件的时候也不会有提示(假如有提示,就不好自动运行了)。但是在任务计划程序中就出现了这样的错误,我猜想是环境的问题,就像 Linux cron 里的环境变量跟正常登录的 shell 不完全一致一样。

    该错误的英文版本是 “Unable to get the SaveAs property of the Workbook class”. 很多时候因为中文的有价值信息太少,我们需要猜测出错信息的英文版本,去搜索英文的资料。不过这次英文资料并没有帮上忙,最后试了一下 SaveCopyAs 这个方法,成功!既然用的是微软的东西,咱也不刨根问底地研究为什么这个方法就可以了──你可能会成为人人景仰的佛,但更可能成为唾弃的疯子。

    把 SaveAs 换成 SaveCopyAs 之后,任务计划程序中可以正常运行了,但是在命令行执行时,却会弹出一个需要确认的对话框……同理,不考虑为什么了,直接以暴制暴,用最简单的方式来解决掉它:

    begin
      workbook.saveas(filename)
    rescue Exception => e
      workbook.savecopyas(filename)
    end
    

    这样,手动执行时使用 SaveAs, 任务计划程序中 SaveAs 会抛出异常,就会使用 SaveCopyAs.

  • 用 CSS3 @font-face 嵌入字体

    今天刚发现牛人 Mark Pilgrim 正在写的 Dive Into HTML5,对网站上标题的字体很感兴趣,查了一下,是 Essays 1743.

    这个字体以 LGPL 协议发布,并没有普及到大部分计算机上,所以需要用到 CSS3 的字体嵌入技术,Cross Browser Font Embedding with the CSS3 @font-face selector 一文详细讲解了跨浏览器的解决办法。

    我已经把本站的头部标题改成使用这个字体,如果你没有看到可能是因为缓存的问题,请刷新一下浏览器。(update: 看久了感觉不太舒服,于是已经换掉了).

    上面提到的教程其实挺麻烦的,主要是 IE 仅支持 eot 格式字体文件。由于我是复制 Dive Into HTML5 的样式,于是直接从那儿把字体文件下载到我服务器上,再把 CSS 代码搬过来就可以了。

    @font-face 定义:

    @font-face {
      font-family: "Essays 1743";
      src: url("/static/font/essays1743-min.eot");
      src: local("Essays 1743"), url("/static/font/essays1743-min.ttf")
    }
    

    在标题应用该样式:

    #header-title {
      font-family: "Essays 1743";
      ...
    }
    

    当然了,嵌入字体的做法对中文来说不大适用,因为一个中文字体文件少说几个到十几个 MB, 用户不能忍受,我们的服务器也不一定能够忍受。所以对中文来说,如果只是想标题使用特殊字体,最好做成图片。而这个英文字体文件只有 30 多 KB,和一张图片的大小差不多,如果有大量的文字需要使用该字体,存储、带宽这方面就划算得多了。

  • 外链点击没有 referrer 信息?!

    最近经常盯着访问日志,有一次一边 “tail -f” 日志,一边在 Google Reader 中点击了一下自己的一个日志(此处“日志”指 blog post)链接,发现新增的一行日志竟然没有 referrer 信息!

    我的浏览器并没有做任何隐藏 referrer 的特殊配置,所以这事儿我纳闷了好多天—— Google 是怎么做到的?即使可以做到,有什么必要隐藏 referrer 呢?

    今天晚上动用了一大堆工具——Firebug, Fiddler, Eventbug, 研究了半天,我想 Google 一定是在用 JavaScript 完成这样的 trick.

    后来突然想明白了,我的 Google Reader 一直是使用 https 连接的(避免意想不到的 connection reset),这不是 Google 做的,而是浏览器的默认行为。这么做很有必要,保护用户的隐私。把 https 换成 http 再点击,发现请求头中确实加入了 referrer 字段。据我所知,SearchStatus 这个扩展在遇到 https 页面的时候也是不会向外作任何查询的。

    根据我做的山寨测试,IE, Firefox, Opera 都是这么做的,很好。微软还有一篇 support article 说这个事,里面提到:

    many secure (HTTPS) Web servers store secure information such as credit-card data in the URL

    我想现在应该很少有网站这么做了,不过 url 里面还是很容易找到涉及隐私的信息。隐藏 referrer 虽然给做 web analytics 的人带来了干扰,仍然是非常必要的。

    在解除这个困惑的过程中,看到几年前就有人发现在 AdWords 中点击广告链接测试的时候,没有 referrer header,很奇怪,这几年内也没有人给他正确的答案。我刚刚给了他一个 comment,希望可以解惑……

    这大概也可以解释为什么我们看到自己网站统计中没多少从 Google Reader 过来的流量吧(至少我的是这样)——因为大家都得 “s”.

  • SQL Server 无法修改表,超时时间已到

    SQL Server 一张表存储大量数据的时候,对表结构作修改就非常耗时了。其实耗时还好说,我们年轻,有的是时间……最怕的是它觉得太耗时就放弃给你修改了。这几天想给某个表加个字段,就遇到了这样的问题。点了保存后过一段时间,就会弹出个对话框说:

    无法修改表。超时时间已到,在操作完成之前超时时间已过或服务器未响应

    解决办法:在 SQL Server Management Studio 里,通过菜单“工具-选项”打开选项对话框。在左侧寻找“设计器-表设计器和数据库设计器”,然后在右侧勾选“为表设计器更新重写连接字符串的超时值”,在它下面的“事务超时时间”默认应该是 30 秒,我们应该把它改得稍微大一些,不过好像不能超过65535.

    微软的软件报错的方式很像某些部门的声明──令人费解,这是它一贯的作风。

    话说我本来是比较不喜欢用 SQL Server 的,尤其是刚开始的时候遇到太多气人的问题,可是由于工作原因又不得不用。不过当那些让人郁闷的问题一个一个解决掉的时候,它也就不那么烦人了。

  • Ruby 的一个陷阱

    今天是 2010-01-25. 我在 irb 中测试 Date 类的 today 方法:

    >> (Date.today -1 ).to_s
    => "2010-01-25"
    >> (Date.today - 1).to_s
    => "2010-01-24"
    >> (Date.today-1).to_s
    => "2010-01-24"
    

    结果多少让人有点吃惊。第一次我输入太快发生了错误,减号和 1 之间的空格被我敲到 1 后面去了,但是两次结果竟然不一样!

    不过我很快回过神来了,第一次输入,Ruby 把 -1 解释成为 today 方法的参数了。因为 Ruby 的方法调用可以不加括号,虽然不鼓励所有的函数调用都这么干,但是去掉一对空的括号是被鼓励的(ref)。例如 puts,我就没见过有人调用它会加括号。

    再看第三个输入,那些对空格很吝啬的人也不会遇到这样的问题,除非他不小心在减号前打了一个空格。运算符和操作数之间的空格竟然影响了程序的解释结果,这让人很纠结。为了保险起见,我还是给这个方法调用加上了一对空的括号。

    假如 Ruby 像其它语言一样要求方法调用必须加括号,这个问题就不会存在。对于解释型语言来说,语法的灵活很可能导致解释效率的降低。不过这么多人喜欢 Ruby,也有一部分原因是它跟其它语言很不一样。

    我忽然想到,如果大学里面有 Ruby 课程(千万不要是必修,把大学变成培训班),肯定会有某些老师把上面的这个小把戏作为考试题,看着学生们出错得意地笑。就如同考察逻辑运算符的优先级一样无聊,其实只要记住括号的优先级最高就行了。

    另外,假如 Ruby 像其它语言一样要求方法调用必须加括号,有的 callback 实现就会更简单。把方法作为参数传递的时候,像 Python 一样直接写方法名不就可以了吗?不行,这是一个方法,方法调用不必要加括号,Ruby 解释器发现了方法名就会尝试执行它。所以得写成 “method(:my_callback)”,才能传入一个 Method object. 又因为这是一个 Method object,所以调用它的时候也不能像 Python 一样简单地写 “callback(…)” 了,需要写成 “callback.call(…)”.

    看来“可省略的括号”使得这种思路的实现复杂化了,不过似乎 block 也是无所不能……

  • Milestone blog-0.2 completed

    2 weeks late…我在用 trac 跟踪自己的业余项目,今天终于 close 了这个 milestone 的所有 tickets.

    除了前几天记录的最新评论和站内搜索两个功能,这个 milestone 还包括:

    • sitemap.xml 生成
    • 更新了旧文章中所有指向旧域名的交叉链接到正确的新域名链接。因为我不光是换了域名,程序、数据库都变了,所以稍微麻烦一些
    • 评论框 Markdown 效果预览

    还有其它好多琐碎的东西。最近的改进大部分都是访问者不太会注意到的。

    另外发现有一大堆 python 的进程,于是为了整洁起见,重启了一下服务器。我给我的程序指定了 fastcgi 的 max_procs 为 1,所以不可能是正常地 spawn 出来的,而很有可能是重启 lighttpd 的时候留下的,看来以后 stop 的时候要杀一下进程了。