<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>结绳以渔</title>
  <icon>https://xinghua.space/white_logo_yao.png</icon>
  <subtitle>临渊羡鱼，不如退而结网</subtitle>
  <link href="https://xinghua.space/atom.xml" rel="self"/>
  
  <link href="https://xinghua.space/"/>
  <updated>2024-04-17T14:13:24.356Z</updated>
  <id>https://xinghua.space/</id>
  
  <author>
    <name>XingHua</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>在场就足够了[Memos]</title>
    <link href="https://xinghua.space/2024/04/17/presence-is-enough/"/>
    <id>https://xinghua.space/2024/04/17/presence-is-enough/</id>
    <published>2024-04-17T14:08:57.000Z</published>
    <updated>2024-04-17T14:13:24.356Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css"><p>从很小开始一直到大学毕业之前，我总是希望春节的时候我爸能在家多待几天。</p><p>其实吧，他在家的时候也没有一直跟我们在一起待着，白天外出打个牌，晚上再出去喝个酒，每天在一起的时间主要就集中在饭点和睡觉前。</p><p>即便如此，那种在场的感觉也是完全不同的。</p><p>工作之后，我成了春节离开家最早的那个了。</p><p>后来我回家时，有时候就坐沙发上看书或者玩儿手机，我妹就说我为啥不多出去走动走动，说说话，我就照搬一直来的想法来回应：每年回家我就坐在这里啥都不说，一切就都不一样了。</p><p>现在想来，很多时候真的只要重要的人在场就很让人感到安慰了，别的都是次要的。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css&quot;&gt;&lt;p&gt;从很小开始一直到大学毕业之前，我总是希望春节的时候我爸能在家多待几天。&lt;/p</summary>
      
    
    
    
    <category term="好好生活" scheme="https://xinghua.space/categories/%E5%A5%BD%E5%A5%BD%E7%94%9F%E6%B4%BB/"/>
    
    
    <category term="Memos" scheme="https://xinghua.space/tags/Memos/"/>
    
  </entry>
  
  <entry>
    <title>精力充沛是好好生活的前提</title>
    <link href="https://xinghua.space/2024/04/06/vigor-is-the-premise-of-live/"/>
    <id>https://xinghua.space/2024/04/06/vigor-is-the-premise-of-live/</id>
    <published>2024-04-06T05:57:21.000Z</published>
    <updated>2024-04-06T06:35:25.687Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css"><h2 id="清明节的三天"><a href="#清明节的三天" class="headerlink" title="清明节的三天"></a>清明节的三天</h2><p>清明节假期的前一天，睡觉提早了半个小时，假期第一天的早上精神抖擞，干劲儿十足，还顺手写了篇博客<a href="/2024/04/04/error-map-is-better-than-no-map/" title="一幅错误的地图好过没有地图">一幅错误的地图好过没有地图</a>。</p><p>我心想提前半小时都有这威力，我直接再提前一点休息还不得起飞了？<br>于是当天尝试了九点睡，半夜三点睡醒了一次，死活无法再次入睡，刷了半个小时的手机，然后又顺利入睡到了七点。</p><p>本以为睡眠充足，昨天应该精神百倍，没想到吃完饭，喝了咖啡，坐在书桌前就开始犯困，哈欠连天，翻了几本电子书，感觉一口气提不上来，又翻了本关于另类数据纸质书，也是觉得无趣。</p><p>于是不装了，上午十点多继续开睡，迷迷糊糊到十二点。起来吃个午饭，心想这下应该睡够了，搞杯咖啡准备直接肝到晚饭。结果状态还是和上午一样，书都拿不住，不到三点感觉还是熬不住，甚至有点生理性头疼。我敲，继续睡特么的。</p><p>然后迷迷糊糊又到五点多，骑车出门吃了个河南菜，路上经过人来人往的大屋顶，才觉得活过来了一点。<br>晚上还是困，但为了回到正常的节奏，硬撑到十一点才上床睡觉，一觉到早上七点半。</p><p>今天早上醒来，终于觉得昨天那种混沌感消失了，又开始干劲儿十足了，高效的看了一上午书。</p><p>这三天对比之下深刻感受到，精力维护真的太重要了，干劲十足，头脑清明的状态和困乏卷顿，脑袋蒙上慢雾的混沌状态完全是两个人。<br>昨天我一度怀疑自己又懒起来了，陆神的影响消失了，这一度让我感受到了堕落的恐惧。但今天再一对比，确认了只是精力问题而不是意愿问题。</p><p>生物钟还是很难轻易打破，现在最适合我的睡眠时段就是十一点到第二天七点半，减去入睡时间，差不多刚好八个小时，一旦偏离这个时间，咖啡当水喝都没什么卵用。</p><h2 id="懒汉与懒妇可能只是精力不足的产物"><a href="#懒汉与懒妇可能只是精力不足的产物" class="headerlink" title="懒汉与懒妇可能只是精力不足的产物"></a>懒汉与懒妇可能只是精力不足的产物</h2><p>懒汉和懒妇大概是这个世界上最让人反感的生物，你想帮他都觉得烂泥扶不上墙。</p><p>我个人不算是精力很旺盛的体质，看八字是五行缺火，精神容易内收。<br>在个人经验中，这一点还真对得上，于是这也潜移默化的变成了一种自我实现的预言。以前很多时候我会觉得精神不足，可能是体质问题。但最近几年的对比生活让我觉得真不是那么回事，不对比，就感知不到到底什么是良好的生活状态。</p><p>充足且适当的睡眠（7~8 小时）+ 持续的运动(对我来说就是不下雨的时候骑自行车上下班，往返 25 公里)， 坚持半年心肺功能和精力就会提升一个层次。只要别随意打破规律，大多数时候日常精力就会非常充沛。</p><p>以前的节假日只想躺着、在书桌前坐不住、懒得做家务等多少有点习得性无助的情况完全消失，我也体会到了陆神那种持续精进的生活中状态。<br>以至于我个人现在非常反感懒汉和懒妇的状态，包括但不限于：</p><ol><li>晚上熬夜不睡，麻木刷手机看剧</li><li>早上懒懒散散起不了床</li><li>白天精神萎靡，能躺绝对不坐</li><li>做家务马虎应付，比如洗碗不清理水池，擦手纸到处乱丢，关窗户不关纱窗，永远的只做 80%。—— 这一点对于保持整洁卫生的环境尤为重要，剩下的那 20% 积累上三天就会让环境变成噩梦</li><li>看书学习做事三天打渔，两天晒网</li><li>…</li></ol><p>但是这些问题，只要保持精力充沛，就可以一点点改善。<br>而要做到精力充沛，一定的自我约束是不可缺少的，特别是对于意义感和使命感缺乏的人来说，甚至需要借助一定的外力约束来完成”启蒙“过程。</p><p>而一旦一个人经历过两种状态的对比，我想没有任何一个人会不喜欢更整洁、更充实的生活。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css&quot;&gt;&lt;h2 id=&quot;清明节的三天&quot;&gt;&lt;a href=&quot;#清明节的三天&quot; class=&quot;</summary>
      
    
    
    
    <category term="好好生活" scheme="https://xinghua.space/categories/%E5%A5%BD%E5%A5%BD%E7%94%9F%E6%B4%BB/"/>
    
    
    <category term="可积累的" scheme="https://xinghua.space/tags/%E5%8F%AF%E7%A7%AF%E7%B4%AF%E7%9A%84/"/>
    
  </entry>
  
  <entry>
    <title>一幅错误的地图好过没有地图</title>
    <link href="https://xinghua.space/2024/04/04/error-map-is-better-than-no-map/"/>
    <id>https://xinghua.space/2024/04/04/error-map-is-better-than-no-map/</id>
    <published>2024-04-04T00:00:03.000Z</published>
    <updated>2024-04-06T06:03:44.902Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css"><p>昨天起床太早，加上中午团建吃饭没来得及午休，晚上十点不到就早早睡了。</p><p>2024 年已经过去了四分之一，下了一夜的雨为清明节更添了一些哀愁，但人在杭州，也没办法去给家乡先辈们的旧坟添上新土。吃完早饭，搞了杯咖啡，开始坐在窗前整理最近的所思所感。</p><p>整个一季度，我最大的积累式收获是读完了《学霸的黑科技系统》，一本被名字耽误的硬核科幻小说。作者的学术视野和文字功底都很扎实，整部作品是以学神陆舟在数学上的探索作为主线，并带着物理、生化、材料、能源、信息学科以及整个人类文明向前发展的故事。</p><p>有人说这本书有一些细节很有问题，还有人说他这个外行都能看出来作者在欺骗外行。</p><p>当然在我看来前者是正常的评价，后者则属于是见识短浅，书也白读了。</p><p>对于我自己来说，这本书进一步增加了我过去一些关键经验的 connect the dots 过程，同时对当今世界中心学科和它们的中心议题有了一个框架性的了解。这也正是我前面说“积累式收获”的原因，积累的前提是存在某种一致性的主线。对我来说，大主线就是对自然世界和人类社会的经验和理解程度，更聚焦的子线就是投资和计算机路线，但正如在<a href="https://xinghua.space/about/">关于我</a>中提到的那样，对世界的理解是更宏大的问题，是基础中的基础。</p><h2 id="Connect-了哪些-dots？"><a href="#Connect-了哪些-dots？" class="headerlink" title="Connect 了哪些 dots？"></a>Connect 了哪些 dots？</h2><h3 id="ACM-校赛、阿黄的超越数、中科大自主招生、小学竞赛"><a href="#ACM-校赛、阿黄的超越数、中科大自主招生、小学竞赛" class="headerlink" title="ACM 校赛、阿黄的超越数、中科大自主招生、小学竞赛"></a>ACM 校赛、阿黄的超越数、中科大自主招生、小学竞赛</h3><p>大学时期参加 ACM 校赛时，有一个问题涉及到超大数，也即超出了 32 位或者 64 位二进制能表达的数字范围。这个时候需要用到一些语言中内置的 long long 类型。当然语言中是否内置了超大数的处理方法不是关键，关键是我在此之前没有任何关于超大数的背景知识，于是就按照正常的整数和浮点数类型设计了算法，结果显然是精度不够，计算偏差很大。</p><p>后来我才知道这是「计算机和 C 语言数据表达精度有限的问题」，我知道这事的第一反应是：<strong>「这特么的大学的 C 语言课堂上根本没教过啊」，这题不是超纲了吗？</strong></p><p>高中时有一次遇到一个挺难的数学题，我感觉自己东拼西凑算出了个答案。跟旁边的阿黄讨论时，他看了一眼结果说：你这个答案是错的，因为问题里是个整系数多项式，而你的答案里却搞了个超越数。我：？？？？？。</p><p>再之前，去县城跑去郑州参加中科大的自主招生，试卷上的题目几乎全是没见过的知识。这特么的<strong>超纲、绝对的超纲</strong>。</p><p>更早的回忆是小学一年级的时候去参加竞赛，结果一塌糊涂。后来听说是只有二三年级，甚至三四年级才可能有那些知识储备。</p><h3 id="一丝明悟：学习曲线的死亡谷和启蒙点"><a href="#一丝明悟：学习曲线的死亡谷和启蒙点" class="headerlink" title="一丝明悟：学习曲线的死亡谷和启蒙点"></a>一丝明悟：学习曲线的死亡谷和启蒙点</h3><p>像上面这样的情况一开始我以为同年龄段的大家都差不多，无非是知道的多点少点，没有质的区别。<br>因此未曾就这件事深究过，不幸的是也没有人能点拨一下，一直到工作几年中遇到了更多的人和更多的事，眼界进一步开阔了之后才逐渐明白到其中的意味。</p><p><strong>1&#x2F; 学习的启蒙点。</strong><br>每个技能或者学科的学习路径上，都存在一个爬坡的临界点，我将其称之为一个真正的启蒙点，含义就等同于康德在《何为启蒙》一文中提到的启蒙。<sup id="fnref:1"><a href="#fn:1" rel="footnote"><span class="hint--top hint--error hint--medium hint--rounded hint--bounce" aria-label="康德的这篇文章非常值得阅读，可参考：http://www.personpsy.org/uploadfiles/file/opentheeyes/culture/2020/什么是启蒙_康德.pdf">[1]</span></a></sup>。<br>过了这个点，学生就走出了死亡之谷，可以自主利用他的理性去探索更广阔的被迷雾覆盖的地图了。<br>而过不了这个点，一旦引导停止，就会在低水平上不断徘徊和重复，甚至向下滑落。</p><p><strong>2&#x2F; 启蒙点的判断。</strong><br>我个人的判断方法是，学生是否根据已经掌握的知识建立了一小块框架地图，是否对未来的走向有模糊的图景，当遇到合适的知识时，不经别人指点，也能够判断出它是否可以放入到已有的地图中产生连接。</p><p>只有这样，才是真正意义上的“师傅领进门”。</p><p>这种时候，他才算具备了<strong>进一步接受大流量信息 input 的基础</strong>。</p><p><strong>3&#x2F; 大流量的信息输入。</strong><br>就后来对自主招生结果的了解来看，的确有很多人能够应付那些对我来说超纲的题目。这个时候我才意识到什么叫”真正的师资“，什么叫”为学有余力的学生准备的信息“。大城市的教师团队视野，可用的学习资源真不是小县城能比的，也造就了一批有天赋且视野非常开阔的学生，对于我们超纲的题目，对于他们来说基本上早都在视野内了。包括后来阿黄跟我提到超越数的时候我心中那种震惊，更是深刻让我感受到了差距，再后来我发现像阿黄这类的学生，大学同学里还有很多。</p><p>而我在刘楼小学读书的时候，家里没有一本课外书，我特眼馋学校那间小图书室，但是一直到毕业也没有像学生开放过，四年级的时候我鼓起勇气向校长借书看，校长说他只有马克思的资本论，我说资本论也行，他说那书连他都看不懂，也就没当回事，最终我也没有借到任何一本书。<br>初中的时候到县城读书真是一件痛苦但又正确的事，我用省下来的钱买了《福尔摩斯》《科幻世界》，还有幸在杂书摊上买了一些课外的科普杂志。尤其是福尔摩斯和科幻世界，它们对我造成的影响值到现在仍然都非常明显。<br>当然那会儿并没有卖学习主线上的进阶读物的，高中时看过的唯一高阶读物是从阿黄那里借来的陈阅增的《普通生物学》，对我影响也很大。</p><p>其实想想也是，根本完全没接触过那些东西的情况下，怎么可能通过知识迁移的方式直接回答那些问题呢？<br>当面对的困难超出掌握的知识面和视野太远，中间的鸿沟是难以逾越的，更何况有时候有些知识并不具备能从更基础的知识推导而出的逻辑， 你不可能在考场上临场通过简单的四则运算直接推算出积分。</p><p><strong>4&#x2F; 彻底放下关于超纲的想法</strong><br>竞赛的意义或许就在这里，它告诉参赛者，这个世界上根本没有绝对意义上的“纲”，也没有所谓的“超纲”。它要求参赛者去开拓视野，去认识更大图景的存在，去积累，把人类已探索区域上覆盖的迷雾一点点揭开，然后去探索图景的边界。</p><p>对于社会经验丰富的人来说，这一点更容易理解，没有人会为你在真实生活中的问题圈定一个认知范围，只需要在认知范围内寻觅便可找到答案。</p><p>而想要放下这个想法，到更大的范围内寻找解决方案，建立一个模糊但全局的框架是重中之重。</p><h3 id="哥伦布与大航海时代的地图"><a href="#哥伦布与大航海时代的地图" class="headerlink" title="哥伦布与大航海时代的地图"></a>哥伦布与大航海时代的地图</h3><p>在大航海之前，欧洲的地图混合了科学、推测和神学元素。这些地图的范围仅限于欧洲、亚洲部分地区和非洲北海岸这些已知的世界，准确性差异很大，比如当时的制图家 Henricus Martellus Germanus 在 15 世纪末所绘制的世界地图 <sup id="fnref:2"><a href="#fn:2" rel="footnote"><span class="hint--top hint--error hint--medium hint--rounded hint--bounce" aria-label="见维基百科词条：https://en.wikipedia.org/wiki/Henricus_Martellus_Germanus">[2]</span></a></sup>：</p><p><img src="https://starding.github.io/picx-images-hosting/image.70a42t8r91.webp" alt="大航海时代前的地图"></p><p>同样在十五世纪末的航海家哥伦布，早期依赖的就是这些充满错误的地图，而随后由他开启的大航海时代从根本上改变了地图制作，当探险家从新的土地返回时，制图师将这些新信息融入到他们的地图中，极大地扩大了世界地图的范围并提高了准确性。</p><p>以事后的眼光来看，早期的地图尽管漏洞百出，但它为人类提供了一个关于世界的宏观框架、一种宝贵的<strong>有限性</strong>。这种有限性和框架性，让一些具备勇气的先锋人物更有底气去探索整个世界，去发现新航道的底气， 而这些探索也终将反过来修复错误，让框架和细节更加精确。</p><h2 id="一幅充满错误的地图要远远好于没有地图"><a href="#一幅充满错误的地图要远远好于没有地图" class="headerlink" title="一幅充满错误的地图要远远好于没有地图"></a>一幅充满错误的地图要远远好于没有地图</h2><p>如果你能够遇到或者找到适合你的老师、教材、小说、文章或者其他任何方法，能够让你拥有一幅自上而下的框架性地图的话，请务必不要错过它，更不要因为别人说 xx 有点小错误就放弃掉这种宝贵的机会。<div id="footnotes"><hr><div id="footnotelist"><ol style="list-style: none; padding-left: 0; margin-left: 40px"><li id="fn:1"><span style="display: inline-block; vertical-align: top; padding-right: 10px; margin-left: -40px">1.</span><span style="display: inline-block; vertical-align: top; margin-left: 10px;">康德的这篇文章非常值得阅读，可参考：<a href="http://www.personpsy.org/uploadfiles/file/opentheeyes/culture/2020/%E4%BB%80%E4%B9%88%E6%98%AF%E5%90%AF%E8%92%99_%E5%BA%B7%E5%BE%B7.pdf">http://www.personpsy.org/uploadfiles/file/opentheeyes/culture/2020/什么是启蒙_康德.pdf</a><a href="#fnref:1" rev="footnote"> ↩</a></span></li><li id="fn:2"><span style="display: inline-block; vertical-align: top; padding-right: 10px; margin-left: -40px">2.</span><span style="display: inline-block; vertical-align: top; margin-left: 10px;">见维基百科词条：<a href="https://en.wikipedia.org/wiki/Henricus_Martellus_Germanus">https://en.wikipedia.org/wiki/Henricus_Martellus_Germanus</a><a href="#fnref:2" rev="footnote"> ↩</a></span></li></ol></div></div></p>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css&quot;&gt;&lt;p&gt;昨天起床太早，加上中午团建吃饭没来得及午休，晚上十点不到就早早睡了。&lt;/p&gt;</summary>
      
    
    
    
    <category term="随笔" scheme="https://xinghua.space/categories/%E9%9A%8F%E7%AC%94/"/>
    
    
    <category term="认知方法" scheme="https://xinghua.space/tags/%E8%AE%A4%E7%9F%A5%E6%96%B9%E6%B3%95/"/>
    
    <category term="可积累的" scheme="https://xinghua.space/tags/%E5%8F%AF%E7%A7%AF%E7%B4%AF%E7%9A%84/"/>
    
  </entry>
  
  <entry>
    <title>Web 小史：关键脉络</title>
    <link href="https://xinghua.space/2024/03/30/a-short-web-history/"/>
    <id>https://xinghua.space/2024/03/30/a-short-web-history/</id>
    <published>2024-03-30T06:38:56.000Z</published>
    <updated>2024-03-31T11:21:10.466Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css"><p>最近两三年，我从 Web 的发展历史中学到了很多，这也符合我个人学习复杂系统的风格：了解旧范式和旧范式的发展，然后转到新范式和前沿的问题。</p><h2 id="Web-的初始范式隐喻：从“一个超文本应用”开始"><a href="#Web-的初始范式隐喻：从“一个超文本应用”开始" class="headerlink" title="Web 的初始范式隐喻：从“一个超文本应用”开始"></a>Web 的初始范式隐喻：从“一个超文本应用”开始</h2><h3 id="1980-年-Tim-Berners-Lee-与-ENQUIRE"><a href="#1980-年-Tim-Berners-Lee-与-ENQUIRE" class="headerlink" title="1980 年: Tim Berners-Lee 与 ENQUIRE"></a>1980 年: Tim Berners-Lee 与 ENQUIRE</h3><p>1980 年 6 月至 12 月，Tim Berners-Lee 在庞大的 CERN <sup id="fnref:1"><a href="#fn:1" rel="footnote"><span class="hint--top hint--error hint--medium hint--rounded hint--bounce" aria-label="European Organization for Nuclear Research, 欧洲核子研究中心，是一个由 23个成员国组成的政府间组织，成立于 1954 年，坐标在法国与瑞士边境的日内瓦西郊梅林">[1]</span></a></sup> 担任独立承包商。</p><p>工作期间，他了解到 CERN 大约有 10,000 名员工，他们的硬件、软件和个人要求各不相同，许多工作是通过电子邮件和文件交换完成的.</p><p>显然他看到了这里面的 Tech Space，也即存在通过技术来促进研究人员之间的信息共享和更新的空间，于是构建了一个名为 ENQUIRE<sup id="fnref:2"><a href="#fn:2" rel="footnote"><span class="hint--top hint--error hint--medium hint--rounded hint--bounce" aria-label="https://www.w3.org/History/1980/Enquire/manual/, 根据伯纳斯-李的说法，这个名字源自于是他小时候看过的，对他影响深刻的一本指南书:《Enquire Within upon Everything》">[2]</span></a></sup> 的新的超文本原型系统。</p><p><img src="https://github.com/starding/picx-images-hosting/raw/master/image.6m3o5wuarl.webp" alt="CERN 坐标"></p><p>以现在的眼光来看：</p><ol><li>这个原型系统其实一个 App 级别的简单的超文本程序，也就是说类似于现在的维基百科，或者 Notion、Flomo、Obsidian 这样的笔记系统。</li><li>其实任何着眼于 App 级别的软件设计都是类似，整个系统会结合需求场景做过多的定义，要求用户必须按照规范来组织内容，这注定了它的扩展性其实有限。</li><li>真正的 Web，需要的是把维基百科、Notion、Flomo、飞书、Google Docs、Obsidian 等各种各样的 App 级别的东西在更高的层次上连接和组织起来的东西。</li></ol><p>显然，只有更高程度的抽象，才能实现这种更通用的能力。</p><h3 id="1989-年-更高的抽象"><a href="#1989-年-更高的抽象" class="headerlink" title="1989 年: 更高的抽象"></a>1989 年: 更高的抽象</h3><p>1980 年末，Tim Berners-Lee 离开 CERN 之后，搞了 3 年和计算机网络有关的业务（那会儿的网络底层是 TCP&#x2F;IP， 上层也有 FTP 等各种应用层协议）。作为一个很有技术理解与业务运转有深刻洞察的人，Tim Berners-Lee 搞的又是实时远程过程调用项目，显然从这段经验中吸收了很多网络的设计思想，然后在 1984 年又回到了 CERN。</p><p>阅历的增长和计算机网络的工作经验让他认识到，寄希望于通过一个 App 级别的工具来统一 CERN 的文档系统是不现实的，他需要通过某种方式链接不同的文档系统（CERN 共存了很多种文档系统，包括他自己搞的 ENQUIRE）:</p><blockquote><p>Creating the web was really an act of desperation, because the situation without it was very difficult when I was working at CERN later.<br>Most of the technology involved in the web, like the hypertext, like the Internet, multifont text objects, had all been designed already.<br>I just had to put them together. It was a step of generalizing, going to a higher level of abstraction, thinking about all the documentation systems out there as being possibly part of a larger imaginary documentation system.<br>But then the engineering was fairly straightforward. It was designed in order to make it possible to get at documentation and in order to be able to get people — students working with me, contributing to the project, for example — to be able to come in and link in their ideas, so that we wouldn’t lose it all if we didn’t debrief them before they left.<br>Really, it was designed to be a collaborative workspace for people to design on a system together. That was the exciting thing about it.</p><p>创建 Web 确实是一种绝望之举，因为我后来在 CERN 工作时，没有 Web 时候的情况非常糟糕（注：指的是多种文档系统工作，协同起来非常痛苦的情况）。<br>其实在哪个时候，与 Web 相关的大多数技术，如超文本、互联网(指底层的 internet，注意它和 World Wide Web 的区别)、多字体文本对象，都已经在实际应用的设计。我只需要把它们放在一起，对(所有的这些东西)进行一些概括抽象，进入更高的抽象层次，将所有文档系统视为可能是更大的一个想象文档系统的一部分。<br>但整体的工程设计相当简单。它的设计目的是获取文档，并让其他人——例如与我一起工作、为项目做出贡献的学生——能参与进来并链接他们的想法，这样即使这些人离职了，我们也不会失去这些想法。<br>实际上，Web 被设计为一个供人们一起在系统上进行设计的协作工作空间。 —— 这就是最让人兴奋的事情。</p><p>—— Academy Achives 2007 年对 Tim Berners-Lee 的采访: Visionary of the Internet <sup id="fnref:3"><a href="#fn:3" rel="footnote"><span class="hint--top hint--error hint--medium hint--rounded hint--bounce" aria-label="原采访见：https://achievement.org/achiever/sir-timothy-berners-lee/#interview">[3]</span></a></sup> </p></blockquote><p>基于这些理念，他设计并提交了 Web 提案 <sup id="fnref:4"><a href="#fn:4" rel="footnote"><span class="hint--top hint--error hint--medium hint--rounded hint--bounce" aria-label="《编制万维网》一书对这段历史有详细的描写">[4]</span></a></sup>, 如下：</p><p><img src="https://github.com/starding/picx-images-hosting/raw/master/image.969iheltq9.webp" alt="Web 提案照片"></p><p>同时还实现了人类第一个 Web 浏览器、第一个 Web 服务器、以及一个 Web 原型站点 <a href="http://info.cern.ch/">http://info.cern.ch</a> <sup id="fnref:5"><a href="#fn:5" rel="footnote"><span class="hint--top hint--error hint--medium hint--rounded hint--bounce" aria-label="Web 20 周年时重建，域名和内容都保持了原状">[5]</span></a></sup></p><p>最早的原型设计包含了三项最核心的技术，仅从名字上就能看出是为”链接不同的超文本系统”而生：</p><ol><li><p>HTML: HyperText Markup Language. 超文本标记语言<br>The markup (formatting) language for the web.</p></li><li><p>URI: Uniform Resource Identifier. 统一资源定位符<br>A kind of “address” that is unique and used to identify to each resource on the web. It is also commonly called a URL.</p></li><li><p>HTTP: Hypertext Transfer Protocol.超文本传输协议<br>Allows for the retrieval of linked resources from across the web.</p></li></ol><p>还是回到现在的眼光来看：</p><ol><li>这三种元素设计高度抽象， 用户只需要遵循几个简单的规范就可以搞一套自己完全控制的文档系统(而不是在别人控制的软件结构中写自己的文档)，或是改造已有的文档系统让它可以连接到其他系统，这构成了现代 Web 的基础框架。</li><li>第一个浏览器，已经是一个可以容纳多个不同网页站点的容器空间。</li><li>这个时候的第一动机是链接不同的文档系统，这和当时的操作系统不同，没有更强的业务流需求驱动，自然也就没有 CSS&#x2F;Javascript 这些后来才出现的东西。</li></ol><p>总的来说，从第一个版本开始，Web 的基本架构就已经确定。<br>在应用层的高度抽象机制（当然比起 TCP&#x2F;IP 这种更底层的抽象还是要具象了很多），天然的分布式开放性、形成了一个巨大的协同空间。</p><p>Tim Berners-Lee 最初的自上而下的设计和其目标已经达到，剩下的就是更加宏大的时代性驱动：个人计算机的发展、基于个人计算机的业务发展、网络开始作为人类活动的告诉信息媒介等等，开始反过来自下而上的驱动 Web 发展。</p><h3 id="1991-年-～-2007-Mosaic、NetScape、IE-三个浏览器"><a href="#1991-年-～-2007-Mosaic、NetScape、IE-三个浏览器" class="headerlink" title="1991 年 ～ 2007:  Mosaic、NetScape、IE 三个浏览器"></a>1991 年 ～ 2007:  Mosaic、NetScape、IE 三个浏览器</h3><p>这个时期是浏览器的早期阶段，期间几个标志性事件是：</p><ol><li><p>1993 年: CGI<br>国家超级计算应用中心 (NCSA) 发布了 NCSA HTTPd Web 服务器，其中包括 CGI 的早期版本。这使得服务端的 Web 程序可以根据网页请求执行，标志着网络上动态内容的诞生。当然那个时候的动态内容很有限，比如提交个表单什么的。</p></li><li><p>1994 年：CSS 被发明<br>CSS 最初由 Håkon Wium Lie 于 1994 年 10 月 10 日提出。1996 年由 W3C 机构背书产生 CSS1 推荐标准。其初始目标是对文档进行更好的排版控制，且主要是文档排版，甚至都没有很规范的“框架布局”机制。</p></li><li><p>1995 年：JavaScript<br>1995 年，在 NetScape 工作的 Brendan Eich 发明了 JavaScript 并在 NetScape 浏览器 2.0 版本中引入。 这显然也是业务上有需求，且是一个新的技术特性，能够让 Netscape 浏览器保持领先。</p></li></ol><p>仍然回到当前视野上来：</p><ol><li>在这一阶段，由于时代背景和具象的需求限制了想象力，我们可以看到很多设计都是自下而上由业务需求驱动的，也没有过多的超前设计。</li><li>CSS 最早目标多是针对文档排版（就像 Word 那样），用于二维网页布局的时候就很吃力，需要通过对一维流式布局的 hack 来实现很多在平面设计领域中很寻常的能力。</li><li>JavaScript 的早期目标是用来处理一些网页中的小任务， 它并不是一个深思熟虑的语言。但好在实现通用图灵机的机制要求是简洁的， JavaScript 也同样是图灵完备的（拥有完整的顺序执行、条件分支执行、循环执行能力），只要 API 足够，它理论上仍然能实现任意其他语言能实现的能力。</li><li>由于 Web 的开放性，当这个系统越来越大之后，网页开发者和浏览器的开发者就需要互相兼容互相迁就，任何一个网页开发者都希望自己的网页能被浏览器正常解析，任何一个浏览器也都希望能解析任何一个网页。这共同形成了很强的已实现技术路径依赖，引入新技术必须要考虑对已有技术的兼容。这保证了开放性和可用性的同时，也为 Web 积累了很大的历史负债。</li><li>各种权威机构背书的标准制订也开始出现，比如 Tim Berners-Lee 领导的 W3C 一直引领 HTML、CSS 的规范制订，古老的 ECMA 机构接手了 Javascript 的标准制订<sup id="fnref:6"><a href="#fn:6" rel="footnote"><span class="hint--top hint--error hint--medium hint--rounded hint--bounce" aria-label="Netscape 于 1996 年向 ECMA International 提交了 JavaScript，部分原因是 ECMA 被认为具有更快的标准化进程，并且已经拥有标准化编程语言的经验。 ECMAScript 标准的第一版于 1997 年被 ECMA International 采用">[6]</span></a></sup>。</li></ol><p>个人认为这三个浏览器以及这些新技术的引入，其实都算是一个思想范式下的产物，其发展路线就是在 Tim Berners-Lee 的浏览器原型上继续前进。</p><p>这个时期用户与内容的互动有限；网页纯粹是信息性的、静态的。但这注定只是一个短暂的阶段性现象。</p><p>因为 Web 的公开性以及便于访问的特点，全人类拥有了一个共同的信息空间媒介，这是以往任何时代都没有的工具。人们的需求量是在是太大了，量变的不断积累会带来质变，自下而上的需求不断驱动 Web 技术的前进，也对整个 Web 工程设计提出了更高的要求。</p><p>当人们对网站的要求不再是一个个简单的文本网页，而是一个完整的，能承载各种业务流逻辑的 App 时，人们对浏览器的要求也从一个单一的网页呈现工具转向一个全能的类操作系统平台。</p><h2 id="Web-范式的转向：从”一个超文本应用“-到-”一个操作系统平台“"><a href="#Web-范式的转向：从”一个超文本应用“-到-”一个操作系统平台“" class="headerlink" title="Web 范式的转向：从”一个超文本应用“ 到 ”一个操作系统平台“"></a>Web 范式的转向：从”一个超文本应用“ 到 ”一个操作系统平台“</h2><p>其实到这里的时候，就回到了我们比较熟悉的事情上了。</p><h3 id="2000-年-～-2010-年-Amazon-云计算服务发展"><a href="#2000-年-～-2010-年-Amazon-云计算服务发展" class="headerlink" title="2000 年 ～ 2010 年: Amazon 云计算服务发展"></a>2000 年 ～ 2010 年: Amazon 云计算服务发展</h3><p>这也是一个时代性的背景，这个时期主要就是远程的计算机集群和操作系统的虚拟化。服务端能力的极速发展，为瘦用户端提供了基础。</p><h3 id="2008-年-V8-引擎"><a href="#2008-年-V8-引擎" class="headerlink" title="2008 年: V8 引擎"></a>2008 年: V8 引擎</h3><p>Chrome V8 Javascript 引擎<sup id="fnref:7"><a href="#fn:7" rel="footnote"><span class="hint--top hint--error hint--medium hint--rounded hint--bounce" aria-label="这个名字来源于一种特定的汽车发动机引擎结构，也即 V8 汽车发动机，所以它不是版本号">[7]</span></a></sup>，极大改进了 JavaScript 的运行时能力和效率。</p><h3 id="2009-年-ChromeOS"><a href="#2009-年-ChromeOS" class="headerlink" title="2009 年: ChromeOS"></a>2009 年: ChromeOS</h3><p>谷歌于 2009 年 7 月宣布了该项目，最初将其描述为一个 Cloud-first 操作系统，应用程序和用户数据将驻留在云中。 ChromeOS 主要用于运行网络应用程序。</p><h3 id="2005年～-CSS3-标准"><a href="#2005年～-CSS3-标准" class="headerlink" title="2005年～ CSS3 标准"></a>2005年～ CSS3 标准</h3><p>CSS3 标准从 2005 年就开始着手制定了。<br>它希望解决对更加动态、交互式的网页设计和布局的需求，这些设计和布局可以适应各种设备（响应式设计）、屏幕和用户交互，具体而言包括 Media 查询， FlexBox 模型、Grid 布局、更丰富的动画能力。<br>在工程化方面，它还将模块化引入 CSS 规范，允许独立开发和采用功能。</p><p>总之，就是加强在不同设备上的布局、交互能力、并且引入更加工程化的设计，以应对越来越复杂的需求。</p><h3 id="2015-年-ECMAScript-6"><a href="#2015-年-ECMAScript-6" class="headerlink" title="2015 年: ECMAScript 6"></a>2015 年: ECMAScript 6</h3><p>2009 年 ES5 发布后，关于下一个版本的讨论几乎立即开始，直到 2015 年正式推出 ES6 标准。<br>ES6 标准最大的改进是原生支持了模块化能力、更方便的异步调用能力、改进了变量作用域、引入了更加面向对象的 Class 语法糖。</p><h3 id="2015-年：PWA"><a href="#2015-年：PWA" class="headerlink" title="2015 年：PWA"></a>2015 年：PWA</h3><p>Google 的 Alex Russell 和 Frances Berriman 创造了“渐进式 Web 应用程序”一词来描述利用现代浏览器支持的新功能的应用程序，包括 service worker、manifests 和其他 Web 特性功能。</p><h3 id="2018-年：Apple-开始支持-PWA"><a href="#2018-年：Apple-开始支持-PWA" class="headerlink" title="2018 年：Apple 开始支持 PWA"></a>2018 年：Apple 开始支持 PWA</h3><p>当然，PWA 和 Apple 的商业生态是存在冲突的，Apple 对 PWA 的支持并不完整。</p><p>同样的，回到现在的眼光来看:</p><ol><li>最基础的范式开始变为“像对待操作系统那样对待浏览器”，有了这个背景之后，整体的工程发展方向就非常清晰了。</li><li>标准的制订其实是落后于实际需要的，CSS3、ES6 这些新标准制订之前，已经由无数种类似的工程实践，比如 CSS 中的各种 hack 布局方式，JavaScript 中的 CommonJS、AMD 模块化规范，jQuery 对文档选择器的封装等。而 CSS3、ES6 标准很大程度上借鉴吸收了这些实践，可以说这些标准是整个 Web 社区推动的结果。</li><li>除了社区推动之外，回到“操作系统隐喻”上的 Web 设计，可以越来越多的借鉴操作系统 App 编程，吸收 Java、Python 等更加深思熟虑的语言设计。</li></ol><p>总之，随着底层技术栈和工程架构能力的逐渐完备，Web 已经成为一个真正意义上的操作系统平台。而 Web Application 也逐渐变得成熟，越来越接近于 Native APP 的体验。</p><h2 id="微信群里的一些讨论"><a href="#微信群里的一些讨论" class="headerlink" title="微信群里的一些讨论"></a>微信群里的一些讨论</h2><p>Web 是信息时代影响最深远的革命性技术（可能都不需要加之一），而且它的发明人 Tim Berners-Lee 还在世，他对 Web 的看法非常值得跟踪。</p><p>本文最早是也是微信群中和 Web 相关的讨论触发，领域新人似乎总会有相似的困惑（这个朋友对一些现象也比较敏感）。</p><p>这里也做一个简短的讨论记录（为了逻辑衔接，对无关内容做了打码处理），来呈现一些具体的场景。</p><p><img src="https://github.com/starding/picx-images-hosting/raw/master/image.5fkcw5ryeo.webp" alt="Web App 讨论 1"><br><img src="https://github.com/starding/picx-images-hosting/raw/master/image.4jnvgpe7v6.webp" alt="Web App 讨论 2"><br><img src="https://github.com/starding/picx-images-hosting/raw/master/image.9nzk7j2rl1.webp" alt="Web App 讨论 1"><br><img src="https://github.com/starding/picx-images-hosting/raw/master/image.58h529r57z.webp" alt="Web App 讨论 1"><div id="footnotes"><hr><div id="footnotelist"><ol style="list-style: none; padding-left: 0; margin-left: 40px"><li id="fn:1"><span style="display: inline-block; vertical-align: top; padding-right: 10px; margin-left: -40px">1.</span><span style="display: inline-block; vertical-align: top; margin-left: 10px;">European Organization for Nuclear Research, 欧洲核子研究中心，是一个由 23个成员国组成的政府间组织，成立于 1954 年，坐标在法国与瑞士边境的日内瓦西郊梅林<a href="#fnref:1" rev="footnote"> ↩</a></span></li><li id="fn:2"><span style="display: inline-block; vertical-align: top; padding-right: 10px; margin-left: -40px">2.</span><span style="display: inline-block; vertical-align: top; margin-left: 10px;"><a href="https://www.w3.org/History/1980/Enquire/manual/">https://www.w3.org/History/1980/Enquire/manual/</a>, 根据伯纳斯-李的说法，这个名字源自于是他小时候看过的，对他影响深刻的一本指南书:《Enquire Within upon Everything》<a href="#fnref:2" rev="footnote"> ↩</a></span></li><li id="fn:3"><span style="display: inline-block; vertical-align: top; padding-right: 10px; margin-left: -40px">3.</span><span style="display: inline-block; vertical-align: top; margin-left: 10px;">原采访见：<a href="https://achievement.org/achiever/sir-timothy-berners-lee/#interview">https://achievement.org/achiever/sir-timothy-berners-lee/#interview</a><a href="#fnref:3" rev="footnote"> ↩</a></span></li><li id="fn:4"><span style="display: inline-block; vertical-align: top; padding-right: 10px; margin-left: -40px">4.</span><span style="display: inline-block; vertical-align: top; margin-left: 10px;">《编制万维网》一书对这段历史有详细的描写<a href="#fnref:4" rev="footnote"> ↩</a></span></li><li id="fn:5"><span style="display: inline-block; vertical-align: top; padding-right: 10px; margin-left: -40px">5.</span><span style="display: inline-block; vertical-align: top; margin-left: 10px;">Web 20 周年时重建，域名和内容都保持了原状<a href="#fnref:5" rev="footnote"> ↩</a></span></li><li id="fn:6"><span style="display: inline-block; vertical-align: top; padding-right: 10px; margin-left: -40px">6.</span><span style="display: inline-block; vertical-align: top; margin-left: 10px;">Netscape 于 1996 年向 ECMA International 提交了 JavaScript，部分原因是 ECMA 被认为具有更快的标准化进程，并且已经拥有标准化编程语言的经验。 ECMAScript 标准的第一版于 1997 年被 ECMA International 采用<a href="#fnref:6" rev="footnote"> ↩</a></span></li><li id="fn:7"><span style="display: inline-block; vertical-align: top; padding-right: 10px; margin-left: -40px">7.</span><span style="display: inline-block; vertical-align: top; margin-left: 10px;">这个名字来源于一种特定的汽车发动机引擎结构，也即 V8 汽车发动机，所以它不是版本号<a href="#fnref:7" rev="footnote"> ↩</a></span></li></ol></div></div></p>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css&quot;&gt;&lt;p&gt;最近两三年，我从 Web 的发展历史中学到了很多，这也符合我个人学习复杂系统</summary>
      
    
    
    
    <category term="作为工程师" scheme="https://xinghua.space/categories/%E4%BD%9C%E4%B8%BA%E5%B7%A5%E7%A8%8B%E5%B8%88/"/>
    
    
  </entry>
  
  <entry>
    <title>重启独立博客</title>
    <link href="https://xinghua.space/2024/02/25/blog-reopen/"/>
    <id>https://xinghua.space/2024/02/25/blog-reopen/</id>
    <published>2024-02-25T08:54:22.000Z</published>
    <updated>2024-03-02T07:08:55.425Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css"><p>可能正如那个传说中的愚昧之巅 - 绝望之谷 - 开悟之坡的曲线一样，人生就是一个接一个的折腾周期。</p><h2 id="往事"><a href="#往事" class="headerlink" title="往事"></a>往事</h2><p>在本博客第一篇文章 <a href="/2016/01/05/hello-world/" title="缘起">缘起</a> 中，我引用了别人总结的写作的三阶段：</p><blockquote><p>第一阶段，刚接触 Blog，觉得很新鲜，试着选择一个免费空间来写。<br>第二阶段，发现免费空间限制太多，就自己购买域名和空间，搭建独立博客。<br>第三阶段，觉得独立博客的管理太麻烦，最好在保留控制权的前提下，让别人来管，自己只负责写文章。</p></blockquote><p>但立下这个 flag 之后，我只在独立博客上写了一年的文字，在续费域名的时候觉得维护独立域名比较麻烦，于是就放弃了独立博客。<br>后续辗转使用了知乎、公众号、小报童这些平台作为自己公开输出文字的地方，本来以为可能会像上面的三个阶段那样，把文字托管到这些地方可以更加专注在写作的本质上，但实际的效果可以说是正好相反。</p><h2 id="机缘"><a href="#机缘" class="headerlink" title="机缘"></a>机缘</h2><p>总结下来，主要有以下几个因素导致我重新回到独立博客</p><p><strong>1. 这些平台使用起来并不方便</strong><br>想在这些平台上公开发布内容？<br>需要先登录网站，加上一番导航操作找到文章发布中心，才能开始写下第一行文字（尤其是知乎和公众号的编辑器，简直是无力吐槽）</p><p><strong>2. 客场作战，不自由</strong><br>几乎每个平台都一个显性的或者隐性的平台规范，什么能写什么不能写，什么写了容易传播，什么写了会石沉大海，这些潜在的东西会影响我的选题，会让我焦虑。</p><p>综合体验下来，几乎所有的写作平台其实都如独立博客写文字方便，独立博客尽管有一些维护工作，但总体来说是比较低频的。而且更关键的是自由。</p><p><strong>3. 我有工程师技能</strong><br>在 20 年从字节离职之后，可能是接触到了新事物，也可能是放下了过去的一些执念，也或许是因为那几年遭遇了很多感情上的，家人健康上的问题，经过几年的挣扎之后，我的视野突然开阔了很多，看清楚了自己的局限，社会的局限，也看清楚了我在这些局限约束下应该做出怎样的选择来继续自己的存在和生活。</p><p>我也真正开始认识到，技术是一个非常有效的杠杆，也是一种生产力，它是一种可以通过创造来做出一些真实改变的东西。<br>创造是重要的，写文章是一种创造，应用自己的技术做一个独立产品也是创造，后者要更强的积累复利效果。</p><p><strong>4. 一些人的影响</strong><br>刘少楠、白光、即刻上在热情的寻找着 small business 的独立开发者们<br>黄龑、九章，这些人的独立博客还在持续存在并且更新着</p><p>在和这些人共处的时候，我能感受到那种努力在这个庞大、混乱、嘈杂的世界洪流裹挟中探索独立性的勇敢。</p><p>总的来说，我开始希望自己也能创造一些更长生命周期的东西，而我在这些年刚好学到了相关的能力。正如三十岁之后定居在了杭州，结束了十多年的漂泊感一样。这两年也越来越希望有一个自己的独立主场，把自己的文字都汇总在同一个地方。</p><h2 id="变化"><a href="#变化" class="headerlink" title="变化"></a>变化</h2><p>在尝试恢复旧博客的时候，我发现以前自己对待文字的态度非常轻浮，从字节离职更换电脑的时候备份了很多资料，但唯独没有把原博客的原始文件备份下来。万幸的是 github 上的仓库里还有编译之后的文件，于是我一篇接着一篇的复原，同时也一篇接着一篇的重新阅读了 16 年的哪些老文章，虽然文笔非常稚嫩，甚至有时候会故弄玄虚，但对我自己来说竟有种常看常新的感受。</p><p>在阅读老文章的过程中，我还发现很多引用外链都已经失效了，这些链接中有的是其他人的独立博客，有的是一些综合站点，甚至还有老的字节 CDN 图床。但是 github、google 相关的链接引用都还可以正常访问。</p><p>8 年确实很长了，很多东西发生了变化或者干脆不存在了，也有一些未曾变过，对比之下让人唏嘘。</p><p>除了这些旧有的恢复工作之外，还有几个变化</p><ul><li>博客名称从「小狐濡尾」变更为了更具象的「结绳以渔」</li><li>用女儿的名字意象设计了新的 Logo（我也开始尝试蒙德里安了哈哈）</li><li>去掉了很多冗余的视觉修饰元素，按现在的审美简化了 UI</li><li>更重视读者的反馈，增加了 Disqus 作为评论区（多说已经没了）</li></ul><p>另外，旧博客使用的 Jacman themes 的技术方案也很老旧了，我 fork 了自己的 theme，开始改进里面已经过时的或是废弃的逻辑，比如把无处不在的 float 布局逐渐迁移到 flex 布局上。</p><p>很多事情做出了选择就无法再回头，好在这件事情可以，在经历了第三方平台 -&gt; 独立博客 -&gt; 回到第三方平台 -&gt; 重新认识到独立博客的好，再回到独立博客这样的反复循环之后，我想接下来会长周期的待在独立博客上了。</p><p>2024.2.25 于杭州·白鹭郡北</p>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css&quot;&gt;&lt;p&gt;可能正如那个传说中的愚昧之巅 - 绝望之谷 - 开悟之坡的曲线一样，人生就是</summary>
      
    
    
    
    <category term="随笔" scheme="https://xinghua.space/categories/%E9%9A%8F%E7%AC%94/"/>
    
    
  </entry>
  
  <entry>
    <title>material design 简介及背后的理论</title>
    <link href="https://xinghua.space/2016/10/31/material-design-introduct-md/"/>
    <id>https://xinghua.space/2016/10/31/material-design-introduct-md/</id>
    <published>2016-10-31T09:04:37.000Z</published>
    <updated>2024-03-02T07:12:07.987Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css"><p>material design<br>—— 将科学引入艺术，让没有什么经验的人也能做出体面的设计</p><p><img src="https://github.com/starding/picx-images-hosting/raw/master/image.pf2jxhz9w.webp" alt="material design"></p><h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>最准确的<a href="https://m1.material.io/">官方介绍</a><sup id="fnref:1"><a href="#fn:1" rel="footnote"><span class="hint--top hint--error hint--medium hint--rounded hint--bounce" aria-label="这是最初版的 material design 官网，2024 年已经更新到 m3 版本">[1]</span></a></sup>：</p><blockquote><p>We challenged ourselves to create a visual language for our users that synthesizes the classic principles of good design with the innovation and possibility of technology and science. This is material design.<br>Develop a single underlying system that allows for a unified experience across platforms and device sizes. Mobile precepts are fundamental, but touch, voice, mouse, and keyboard are all ﬁrst-class input methods</p><p>我们用了洪荒之力，为用户设计了一种视觉语言，它综合了传统设计原则中好的部分，以及科学技术带来的创新和可能性等。这就是 material design。<br>（material design 可用来）开发一套基准系统，在这个系统的基础之上，构建跨平台和超越设备尺寸的统一体验。它遵循基本的移动设计定则，同时支持触摸、语音、鼠标、键盘等输入方式</p></blockquote><p><strong>设计原则</strong></p><ol><li><p>material（材料）其实是一个隐喻：<br>这个隐喻是理解 material design 其他内容的基础。在考虑 material 设计空间以及一系列元素动作行为设计的时候，都不要忘记背后的隐喻。</p></li><li><p>鲜明，形象，精心设计（就是说设计上是预先安排的，设计后面存在预设动机）<br>借鉴传统印刷平面设计规范——排版、网格、空间、比例、配色、图像使用——来指导视觉处理。这些规范不仅仅能讨好眼球，同时还拥有建立层次，赋予意义和引导焦点上的意义（多是认知心理学上的意义，后面会谈到）。</p></li><li><p>有意义的动画效果<br>动画是前端交互中非常重要的一部分，但是 material design 的动画运用并不是随意的，它从现实中抽象而来，并且符合用户的认知模式。</p></li></ol><p>下面我们就对官方的这个概括做一个解读</p><h2 id="Material-Design-背后的“科学技术”"><a href="#Material-Design-背后的“科学技术”" class="headerlink" title="Material Design 背后的“科学技术”"></a>Material Design 背后的“科学技术”</h2><h3 id="从传统平面设计中汲取营养"><a href="#从传统平面设计中汲取营养" class="headerlink" title="从传统平面设计中汲取营养"></a>从传统平面设计中汲取营养</h3><p>在官方介绍中提到，material design「综合了传统设计原则中好的部分，科学技术带来的创新和可能性」。其中的「传统设计原则」比较容易理解，早在印刷时代，在如何将信息以更美好，更容易让人接受的形式展示出来上面，人们已经做了很多探索，并且总结出了一些行之有效的平面设计原则：</p><ul><li>一致性</li><li>减轻记忆负担</li><li>对齐，相关</li><li>…<br>这些最初用于传统纸质媒介的设计准则，被搬到新的电子媒介上来并且取得了很好的效果——要知道网页刚开始除了页面上有一些超链接外，其他展现方式跟纸质媒介中的丰富性相差甚远，传统平面设计中的理念能对 web 设计产生非常有用的指导，比如网格系统：<br><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.42f393xkglk0.webp" alt="平面设计中的网格系统"></li></ul><p>随着 web 的发展，电子媒介就有了自己独特的地方，不再像纸质媒介那样是纯静态的了——它有了真正的「交互」。新的 web 特性也需要寻求其他的理论支撑，如果不能再从传统的平面设计中借鉴，如何开创一套适用于 web 这些新特性的设计准则？这就来到了 material design 文档中所说的「科学技术带来的创新和可能性」。</p><h3 id="开拓新的设计领域"><a href="#开拓新的设计领域" class="headerlink" title="开拓新的设计领域"></a>开拓新的设计领域</h3><p>如果传统平面设计不能直接借鉴，那么就看看平面设计背后有没有可以深入挖掘的内容。在寻求理论的支撑时，需要向还原理论方向更深处寻找，至于还原论的方向，简单来说如下：</p><blockquote><p>设计的基础是心理<br>心理的基础是生物<br>生物的基础是化学<br>化学的基础是物理</p></blockquote><p>虽然这些概括的命题争议很大，在这些学科中至少可以说「部分如此」。在设计上往更深层次寻找，基本上到「心理，生物」这一范围。找到更深层次的理论，就为「创造性」设计提供了基础，使得设计空间的表达可以发生转变，也不必再囿于传统平面设计在新 web 媒介下的套用，完全可以根据这些深层理论进行自由发挥，创造出适合 web 的设计形式。</p><p>说了这么多，那么这些科学技术上的创新，可能性，指的究竟是哪些内容？</p><h3 id="认知心理学"><a href="#认知心理学" class="headerlink" title="认知心理学"></a>认知心理学</h3><p>在说认知心理学之前，先来看一个来自头条圈的小例子：</p><p><img src="http://p3.pstatp.com/obj/c8f0005d14632f84a10" alt="头条圈图标投票调查"></p><p>这个小例子多少说明了认知在前端界面中的地位并不像人们想象中的那么低，不过很多人都没有意识到这有多重要。</p><p>人类认知事物的过程（感知，学习，推理，记忆等）是具有某些固定模式的，人们在前端领域所进行的认知行为也没有脱离这个范围。这些模式的形成基于人类的生物学结构，虽然工业革命以来，人类自身和所处的环境被迅速地改造，但是进化毕竟是以百万年为单位的，人类生物结构上的进化已经早已基本完成，在可以预见的时间内，这种生物结构也将一直保持稳定。在心理学上，已经有不少结论可以对设计有所教益：</p><ul><li>经验，环境，目标对认知的影响</li><li>心理上的格式塔现象</li><li>短期记忆与长期记忆</li><li>阅读行为的研究</li><li>决策心理</li><li>…</li></ul><p>上述所列研究在设计中都有所应用，而关于为什么要讨论认知心理学，《认知与设计》中有这样一段话（稍有增改）：</p><p>因为遵循用户界面设计准则不像遵守烹饪食谱那么按部就班。设计准则经常描述的是目标而不是操作。它们特意及其概括从而具有更广泛的适用性，但这也意味着，人们对它们准确的意义和在具体设计情景上的适用性经常会做出不同的诠释</p><p>更复杂的是，对于一个设计情景，经常会有多个规则看起来都适用。这就要求要对不同的设计之间做出权衡，而权衡的依据不能仅凭设计师个人喜好，需要有相应的数据，理论支撑。数据可以从运营哪里得来。</p><p>而理论只能求助于更深层次的认知心理学</p><p>在了解用户认知模式的情况下，就不容易出现「符合设计原则，但不符合用户认知」，导致用户体验不好的情况。比如上面所举例子中，给… 加上修饰，是符合不少设计规则的——更一致，跟其他图标相容性更好，更加显眼等，但它是不符合认知的，用户在此很容易出错。</p><p>人类身处现实世界之中，而思维有时则在互联网中畅游，这就在现实环境与互联网环境中产生了一种「语境转换」——人们会根据现实中的某些特点来认知互联网中的事物，比如垃圾桶代表回收站等等。借助于心理学，可以做到从现实到互联网设计的较为平滑的认知过渡。对于运动效果也是同样，在真实世界中发生的运动都是平滑的，不会出现折线运动（撞击除外）。这也是平滑过渡的运动看起来自然的原因，而且由于这种自然性，也更容易给人熟悉感，更容易被人接受。</p><p>另一个产生「语境转换」的地方是应用中不同场景的切换，需要精心设计转场动画进行视觉引导，从而使过渡更加自然和平滑，让人的思维不至于断层，贝塞尔曲线也是在这种意义上得到了充分的应用。<br><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/keynote_animation_material_design.3wdz6hrupme0.gif" alt="material design motion gif"></p><h3 id="生物学"><a href="#生物学" class="headerlink" title="生物学"></a>生物学</h3><p>主要是进行生物结构特性上的研究，认知心理学可以在此寻求理论基础，比如：</p><ul><li>脑神经科学</li><li>眼动研究</li><li>眼球成像模式研究</li><li>这些研究更为的基础而且多少会涉及到进化论上的内容，这里不进行展开，举一个关于眼球感光细胞的理论：</li></ul><p>人类视野的空间分辨率从中央向边缘锐减，有如下三个理由</p><blockquote><p>像素密度<br>每只眼睛有 600 到 700 万个视锥细胞，它们在视野中央（一个很小的叫做中央凹的区域）的分布比在边缘紧密的多（对应中央视觉）。中央凹没平方毫米有约 158000 个视锥细胞，而在视网膜的其他部分，每平方毫米只有 9000 个视锥细胞（对应边界视觉）。</p><p>数据压缩<br>中央凹的视锥细胞与视觉信息处理和传导的起点——神经节细胞——的连接比是 1:1，而视网膜的其余地方，多个光感细胞（视锥细胞和视杆细胞）才与一个神经节细胞相连。用术语来说，边界视觉的信息在被传递到大脑之前是经过压缩（数据有损）的，而中央视觉不是。</p><p>资源处理<br>中央凹仅占视网膜面积的约 1%，而大脑皮层却有 50% 的区域用于接受中央凹的输入，另一半处理来自占视网膜 99% 的区域的数据。</p><p>这导致我们视野中央的视觉分辨率要远远高于其他地方，而在一臂距离下，眼球的中央凹视觉面积大概像拇指指甲那么大，也就是你当前在屏幕上看的三个字宽度左右——这就是视觉焦点的基础。</p><p>——《认知与设计》 [美] Jeff Johnson（引文略有改动）</p></blockquote><p>关于眼睛的生物学研究告诉我们，人类在观看屏幕时，其视觉焦点基本只有拇指指甲盖大小，在此之外的视野都是「边界视野」。在这种视觉模式基础上，如何进行视觉引导，把用户的注意力引向那些希望用户看到的信息上面，也是一个挑战。最直接的一个例子是输入框出错时，错误提示放置的位置，出现的方式等等。</p><p><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.4ni1tz3a4oi0.webp" alt="表单错误提示"></p><h2 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h2><h3 id="物理学上的抽象-合理的量化"><a href="#物理学上的抽象-合理的量化" class="headerlink" title="物理学上的抽象 &amp;&amp; 合理的量化"></a>物理学上的抽象 &amp;&amp; 合理的量化</h3><p>material 的官方介绍中，还提到<a href="https://m1.material.io/material-design/introduction.html#introduction-principles">「material is metaphor」</a>，material 是个隐喻，隐喻什么？</p><p>material design 所隐喻的是一种设计材料（material），姑且称之为「material 卡片」是从现实中抽象出来的，去掉现实中的杂质和随机性，保留空间关系、变化与过渡，光影效果。这种材料具有厚度，材料之间有空间关系。这其实暗示着一个更大的隐喻 —— 整个 material design 其实隐喻着一个特殊的设计空间，这个空间具有三维结构，而 material 卡片则是组成这个空间的基本材料。</p><p><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.3bcaojsh32g0.webp" alt="material environment"></p><p>为什么要费这么大的功夫，来抽象一种设计材料，抽象出一种虚拟空间？<br><strong>因为材料和构建规则一起决定了一致性</strong></p><p>为了理解这件事情，我们可以从真实世界中的建筑设计入手：<br><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.5y74kebkgds0.webp" alt="建筑图"></p><p>所有的设计都可以形象的称之为「带着镣铐跳舞」，这一点在建筑设计上尤为明显。在现实中的建筑设计，要求采用基本的砖块，混凝土，钢材，玻璃等可用的原料，做出出符合真实世界物理规律的设计。</p><p>要知道世界上大多数建筑物都是大同小异的，只有少部分设计师才能设计出既符合规则，又超脱于世俗的建筑。</p><p>如果材料和规则限制太大，则会造成表现形式上的死板，material design 虽然抽象于现实世界，但是也增加了现实中所不存在的魔法特性，，比如 material design 中的卡片可以随意拆解，合并，变形等等。</p><p>MD 中存在一些量化标准，这些量化标准为设计提供了一种更强一层的规范作用：</p><ul><li>卡片厚度</li><li>卡片高度差</li><li>颜色选择</li><li>动画时间<ul><li>连续图像之间可以形成视觉融合的最长间隔：20ms</li><li>一个视觉事件与我们对它完整感知之间的时间差：100ms</li><li>事件进入意识的编辑“窗口”：250ms</li><li>…</li></ul></li></ul><p>这种「有根据地量化设计」观念是超前的，它使设计不再是那些具有丰富经验的大师们的专属，不再是灵感的迸发和单纯个人喜好的表达。如果你了解一些科学史，就能明白这种在设计语言上「将科学引入设计」的行为的重要性。如果做个对比的话，相当于是在向来以神秘方式进行的炼金术中，引入了量化的科学的方法——它变成了化学。</p><p>在更早的设计中也可以见到科学与技术结合的影子，但是没有一种能像 material design 这样，借助一种隐喻空间的形式，如此彻底地进行设计上的改造与规范。<br>上述这些特点，可以说是「让经验不多的人，也能做出体面的设计」的原因。</p><h3 id="让经验不多的人也能做出体面的设计？"><a href="#让经验不多的人也能做出体面的设计？" class="headerlink" title="让经验不多的人也能做出体面的设计？"></a>让经验不多的人也能做出体面的设计？</h3><p><strong>什么是体面的设计</strong></p><ul><li>视觉上具有美感</li><li>有利于信息的精确传达</li><li>背后有心理学基础，符合用户的认知习惯（而不仅是设计者个人喜好）</li><li>material design 已经将上述东西融入到语素之中了，所以借助 material design 进行前端的设计在某种程度上决定了它的下限——不会特别烂。</li></ul><p>Material Design 试图在艺术和科学之间找一个设计点，这是可能的——虽然它对设计者的要求非常高。</p><p>在我看来，Material Design 是部分做到这一点了，它拥有非常清晰和极具启发性的思路。即使某天作为整体的 Material Design 消解了，也会有很多极富启发性的思想被延续下去。</p><h2 id="Material-Design-思维导图"><a href="#Material-Design-思维导图" class="headerlink" title="Material Design 思维导图"></a>Material Design 思维导图</h2><p><img src="http://p3.pstatp.com/obj/c900003e766a96e94a6" alt="MD 思维导图"></p><p>上图是根据 Material Design 设计准则整理出来的思维导图，右侧几个分支叙述了 Material Design 包含的最基本的组件，结构。左侧的分支则介绍了一些经验性的最佳实验，读者可以根据前面的叙述，看看能否在背后找到这些原理，技术的痕迹。</p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><h3 id="超链接："><a href="#超链接：" class="headerlink" title="超链接："></a>超链接：</h3><p><a href="https://m1.material.io/">material design 官网</a><br><a href="https://www.zhihu.com/question/24276657/answer/27262112">如何理解 Google 的 Material Design 设计语言？</a><br><a href="https://www.theverge.com/2014/6/27/5849272/material-world-how-google-discovered-what-software-is-made-of">The Verge 对 Matias Duarte 的访谈</a></p><h3 id="书籍"><a href="#书籍" class="headerlink" title="书籍"></a>书籍</h3><p>《平面设计中的网格系统》<br>《认知与设计——理解 UI 设计准则》<br>《Don’t Make me think》<div id="footnotes"><hr><div id="footnotelist"><ol style="list-style: none; padding-left: 0; margin-left: 40px"><li id="fn:1"><span style="display: inline-block; vertical-align: top; padding-right: 10px; margin-left: -40px">1.</span><span style="display: inline-block; vertical-align: top; margin-left: 10px;">这是最初版的 material design 官网，2024 年已经更新到 m3 版本<a href="#fnref:1" rev="footnote"> ↩</a></span></li></ol></div></div></p>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css&quot;&gt;&lt;p&gt;material design&lt;br&gt;—— 将科学引入艺术，让没有什么经验的</summary>
      
    
    
    
    <category term="作为工程师" scheme="https://xinghua.space/categories/%E4%BD%9C%E4%B8%BA%E5%B7%A5%E7%A8%8B%E5%B8%88/"/>
    
    
  </entry>
  
  <entry>
    <title>前端工程师的形而上学 (0)</title>
    <link href="https://xinghua.space/2016/09/04/fe-metaphysics/"/>
    <id>https://xinghua.space/2016/09/04/fe-metaphysics/</id>
    <published>2016-09-04T09:00:35.000Z</published>
    <updated>2024-03-02T07:10:19.177Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css"><p>形而上学… 我是想说说除了技术之外的事。<br>文章会经常修改</p><h2 id="初衷"><a href="#初衷" class="headerlink" title="初衷"></a>初衷</h2><p>前端工程师是一个很特别的职业，借用一句优雅的话来说——既是画家，又是黑客。从产品链上来看，前端工程师位于服务端与设计师之间，是工程和设计之间的桥梁。</p><p>这要求前端工程师不仅仅要关注工程上的事，同时还要留意产品设计、用户体验这一端的内容。然而就我身边来看，很多前端工程师在工程上的积累要比另一端深厚的多。</p><p>这个系列文章就是要介绍一些前端工程中，偏向「人文」的知识，以及本系列文章尽量只描述能够「以理说文」的部分。</p><h2 id="以理说文？"><a href="#以理说文？" class="headerlink" title="以理说文？"></a>以理说文？</h2><p>以设计和心理学的关系举例来说：</p><blockquote><p>生物的基础是化学，化学的基础是物理</p></blockquote><p>在自然科学领域，有一种思想影响深远——还原论（Reductionism）。上面那句话的意思大概是：所有的生物现象，最终都可以追溯到生物体内的各种各样的化学现象。而所有的化学现象都可以追溯为各种各样粒子的组合，运动。<br>虽然关于还原论有非常多的争议，但是从自然科学的发展历史来看，它是研究中可理解的最有效的方式，通过还原分析的形式产出了大量的成果，因此也被其他社会学科（心理学，经济学）所借鉴。<br>现代心理学不过百年历史，二十世纪六、七十年代起，随着医疗科技和实验方的进步，例如 EEG（脑电图）和 MRI（磁共振成像）等技术的出现，为认知心理学、脑神经心理学等研究领域带来高速的发展，同时也为心理学带来了支持还原论的基础。</p><blockquote><p>心理学的基础是生物</p></blockquote><p>这句话的争议或许更多一些，但利用还原论的思路，至少可以在部分现象上往生物学层次更进一步。</p><blockquote><p>设计的心理学基础</p></blockquote><p>一路类比下来，在设计领域也是有部分内容是可以找到更为普适的心理学依据的，比如很多设计原则中提出的：对齐，靠近，对比等等。这就为设计提供了一种「普适的说明性基础」，让设计不再看起来只是设计师的个人喜好传达，当遇到一些设计上的不同意见时，可以找到（比 AB 测等数据验证）一种更为轻松的解决方式——咱们往下还原一步看看怎么说。</p><h2 id="路线"><a href="#路线" class="headerlink" title="路线"></a>路线</h2><p>大概会是设计心理学——信息媒介——技术哲学<br>水平有限，欢迎交流，拍砖</p>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css&quot;&gt;&lt;p&gt;形而上学… 我是想说说除了技术之外的事。&lt;br&gt;文章会经常修改&lt;/p&gt;
&lt;h</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>前端工程师的形而上学 (1)—— 一个例子</title>
    <link href="https://xinghua.space/2016/08/29/why-users-can-not-see-collect-function-in-neihan/"/>
    <id>https://xinghua.space/2016/08/29/why-users-can-not-see-collect-function-in-neihan/</id>
    <published>2016-08-29T08:44:10.000Z</published>
    <updated>2024-03-02T07:15:59.532Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css"><p>本文介绍一个认知心理学在「内涵段子」（支持一下公司产品）app 上的应用。</p><p>经常听到内涵段子的运营收到用户「内涵段子有没有收藏功能」的反馈，数量之多让人不由得疑惑，为什么这么多用户看不到内涵段子的「收藏」「保存」这几个功能？明明它们就在点击分享时弹出的面板上，按理说应该一眼就能看到。</p><p>这其实是一种心理学上的盲视现象，当然一旦你知道有这两个功能并且有意识的去留意时，这种盲视现象就消失了。不过对于不少用户来说，这是个困难的过程。本文就从认知心理学角度来分析一下这个匪夷所思的问题，并且给出相应的解决方案：</p><h2 id="精简版结论"><a href="#精简版结论" class="headerlink" title="精简版结论"></a>精简版结论</h2><h3 id="两步分析"><a href="#两步分析" class="headerlink" title="两步分析"></a>两步分析</h3><p>进入分享弹层之前，分享图标带有强烈的目标引导倾向（就是分享），让人下意识的认为点击这个图标之后的弹层全部功能都与分享有关。</p><p>内涵段子分享图标：<br><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.5htfc054ky80.webp" alt="内涵段子分享图标"></p><p>进入弹层之后，受目标影响，关注点都在分享功能上，从而导致对其他功能的盲视，而下面那些功能图标风格接近 ios 系统风格，更是加剧了这种盲视效果。（下图为点击后的弹层，注意下面的「收藏」「保存」功能）<br><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.26yvaxxkqnms.webp" alt="收藏和保存功能"></p><p>用户眼中其实是这样的 (用户只看到两个点，当分享时看到上面一个点，取消时会看到下面一个点，至于中间的部分一般一眼扫过，被忽略掉)：<br><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.1pfm7einwsf4.webp" alt="用户眼中的分享面板"></p><h3 id="如何改进"><a href="#如何改进" class="headerlink" title="如何改进"></a>如何改进</h3><p>其实很简单，有两个方向</p><ol><li>分享图标换成 … （表示更多功能）：因为对于此图标，用户心理预期就是点开之后里面有多种功能可选，从而会较为留心的查看。</li><li>分享图标就是分享功能，单独拆出来（单一图标等于单一功能的心理预期），剩下的用 …（更多功能）表示</li></ol><p>以上不管哪个方向，都需要改变「收藏」「保存」等功能图标的风格，避免跟系统的过于接近，最好是跟内涵风格保持一致。</p><p>想深入了解分析过程的童鞋，可观看完整版文章。主要从一些心理认知理论入手进行分析，文中包含了一些当前认知心理学领域的很有趣的观点，推荐阅读。</p><h2 id="完整版的分析过程"><a href="#完整版的分析过程" class="headerlink" title="完整版的分析过程"></a>完整版的分析过程</h2><h3 id="两个问题（要是有投票就好了）"><a href="#两个问题（要是有投票就好了）" class="headerlink" title="两个问题（要是有投票就好了）"></a>两个问题（要是有投票就好了）</h3><ol><li>你有没有留意到「内涵段子的收藏，保存功能」？</li><li>如果留意到了，从使用段子开始到留意到花了多长时间？</li></ol><p>为了描述一个用户使用内涵段子的完整心理，所以加入我个人的使用内涵的经历，不想了解的可以跳过此段落，直接看第二个大标题段落。</p><h3 id="内涵使用经历背景"><a href="#内涵使用经历背景" class="headerlink" title="内涵使用经历背景"></a>内涵使用经历背景</h3><p>到今天为止，我使用内涵段子 app 差不多有半年的时间。在使用过程中让我最疑惑的地方是，有时候遇到一个很喜欢的图片或段子想保存或者收藏下来，但找不到相应的功能。</p><p>作为一名工程师，我自认为使用 APP 的经验非常丰富，但我的的确确没有发现类似功能。最后我只能猜测是出于某些特别的考虑，pm 没有设计这两个功能。以及为了收藏我喜欢的一些段子，只能把它直接分享到我个人的微信中，如下图（很蠢但我没找到好办法）：<br><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.1mk4pz687fgg.webp" alt="通过微信保存我的分享"></p><p>今天第一次参加内涵相关的需求讨论会时，我又想起这个问题，于是问了一下相关的负责人，被告知是有「收藏」「保存」功能的，只是我没有发现（一般人试图找了几次无果后，基本就放弃寻找了，转而用其他手段代替）。</p><p>于是我挨个把所有能看到的图标，全遍历了一遍，千真万确，最后我发现了几个被我忽略近半年的功能 —— 因为某些原因，这些功能被盲视了，即便我曾无数次的点击分享图标。如下图所示，收藏和保存功能就在弹层下方：<br><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.5htfc054ky80.webp" alt="内涵段子分享图标"></p><h3 id="为什么「收藏」「保存」功能被盲视了？"><a href="#为什么「收藏」「保存」功能被盲视了？" class="headerlink" title="为什么「收藏」「保存」功能被盲视了？"></a>为什么「收藏」「保存」功能被盲视了？</h3><p>这可以从认知心理学上找到原因。简单来说，主要有四个原因（不展开了，只说结论）：</p><p>人的视线焦点集中区域（中央视野）非常窄，在正常屏幕距离下（半臂到一臂距离），我们的视线焦点大概只有拇指指甲盖大小。<br>人的注意力非常有限，普通人查看手机时注意力基本只能集中于一点（通常是视线焦点）<br>人的注意力很容易被目标引导，跟目标相关性强的容易被注意，反之容易被忽略<br>人对事物的认知会受经验和习惯的影响</p><h3 id="操作步骤分析"><a href="#操作步骤分析" class="headerlink" title="操作步骤分析"></a>操作步骤分析</h3><h4 id="点击分享图标"><a href="#点击分享图标" class="headerlink" title="点击分享图标"></a>点击分享图标</h4><p>分享图标：<br><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.1pfm7einwsf4.webp" alt="分享图标"></p><p>有互联网产品使用经验的人对这个图标非常熟悉，一般是想要分享才会点击这个图标。注意这里的因果关系，一般不是先点了这个图标，再决定是否分享，而是一开始就带有目的性。</p><p>这个分享图标太常见了，以至于会设定一种强代表性（也带有强引导性）：图标即功能，在熟练使用互联网的人看来，分享图标与分享功能这二者是一一对应的（如果出现了分享之外的功能，则是不符合用户心理预期的）</p><p>上面两点综合起来决定了用户点击这个图标的预期——就是奔着分享去的，我进这个页面会看到分享功能（也是前面认知理论的 3，4 点）</p><h4 id="进入分享弹层"><a href="#进入分享弹层" class="headerlink" title="进入分享弹层"></a>进入分享弹层</h4><p>功能弹层：<br><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.5htfc054ky80.webp" alt="内涵段子分享面板"></p><p>进入分享弹层之后，由于用户实现有了目标和预期并且受其影响，他的视线和注意力是这样的（根据前面的认知理论，用户的视线焦点范围很小，这个焦点只会放在最值得关注的地方），如下图：<br><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.1x5dtdlzl3mo.webp" alt="用户眼中的分享面板"></p><p>如果用户不想分享了，按照经验习惯直接把目光跳到底部，这个时候他的视线焦点和注意力如下图：<br><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.6pbzkr4oook0.webp" alt="用户眼中的分享面板"></p><p>被盲视的另一个原因<br>头条分享弹层 &amp;&amp; 内涵分享弹层</p><p>头条：<br><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.2gyyac07p2w0.webp" alt="今日头条分享面板"></p><p>内涵：<br><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.5htfc054ky80.webp" alt="内涵段子分享图标"></p><p>对比可以发现，内涵的分享弹层下部按钮风格跟 ios 的风格设定非常接近，而且这种风格采用浅灰色线条式设计，视觉敏感度很低（不容易被边界视觉留意到）。用户再结合自身使用 ios 的经验，下意识会认为这部分只是系统自带的一些杂七杂八的功能，从而视线直接扫过不看，导致信息丢失。</p><h3 id="如何改进-1"><a href="#如何改进-1" class="headerlink" title="如何改进"></a>如何改进</h3><p>其实很简单，有两个方向</p><p>分享图标换成 … ，表示更多功能，因为对于此图标，用户心理预期就是点开之后里面具有多种功能，从而会较为留心的查看。</p><p>分享图标就是分享功能，单独拆出来（单一图标等于单一功能的心理预期），剩下的用 …（更多功能）表示</p><p>以上不管哪个方向，都需要改变「收藏」「保存」等功能图标的风格，避免跟系统的过于接近，最好是跟内涵风格保持一致。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css&quot;&gt;&lt;p&gt;本文介绍一个认知心理学在「内涵段子」（支持一下公司产品）app 上的应用。&lt;</summary>
      
    
    
    
    <category term="作为工程师" scheme="https://xinghua.space/categories/%E4%BD%9C%E4%B8%BA%E5%B7%A5%E7%A8%8B%E5%B8%88/"/>
    
    
  </entry>
  
  <entry>
    <title>毕业一年</title>
    <link href="https://xinghua.space/2016/07/29/one-year-after-graduation/"/>
    <id>https://xinghua.space/2016/07/29/one-year-after-graduation/</id>
    <published>2016-07-29T08:26:03.000Z</published>
    <updated>2024-03-02T07:13:47.169Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css"><h2 id="毕业一年"><a href="#毕业一年" class="headerlink" title="毕业一年"></a>毕业一年</h2><p>还记得结束近二十年学校生活时茫然不知所措的情景，搬到龙泽出租房中第一夜的难以入眠也似乎就在昨天。然而转眼间，已经毕业一年了。</p><h2 id="工作"><a href="#工作" class="headerlink" title="工作"></a>工作</h2><p>至今耿耿于怀，考研哲学因一分之差未能进入复试。最终临到毕业前，我又回到了计算机这个行业上。</p><p>回忆起来，我竟从未有过只言片语来回味那时的考研生活，也许是思绪淹没在近一年繁忙的工作中，未能抽身吧。从大三暑假开始就将精力集中在了科哲的备考上，那大概是大学四年最充实的日子：每天泡在图书馆，从古埃及，古两河流域到古希腊，再到罗马，伊斯兰，近代欧洲。我了解到了科学的历程，哲学的发展，近代科哲和技术哲学的崛起，东西方文明的不同。甚至考场中的胃疼，考试结束时略显浮夸的朋友圈动态都还记得清清楚楚，然而终究是跪在了北大门前。对现实和年龄妥协，从此与科哲专业无缘。但是技术哲学带给我的思考方式已经融入到我的思考方式中，不管是日常生活上，还是工作上会让我一直受益。</p><p>带着忐忑的心开始求职，去了一个学长创办的创业公司，不清楚是自己无知，还是公司对自己过于信任，第一次出来面试，就直接入职了。后来因为这和家人朋友还发生了一些争执，果真是年少轻狂啊。此外还有些在现在看来有些装 B 的疑惑：都说找工作难，但这是什么情况？不过也没多想，紧迫的毕业，入职，开始了职场菜鸟的生活，计划中的毕业旅行也取消了。</p><p>我想我还是算幸运的，由于大三暑期以及几乎整个大四都在准备考研，导致在计算机上的实习经历几乎为零——碰到实际项目时，捉紧见着。不过之后在公司受到了良好的引导，也慢慢获得了相当程度的重视，逐渐改善了情况。就这样度过了辛苦但是积极向上的半年。这半年中，真的有一种初生牛犊不怕虎的心态，基本各种意见各种想法都敢提，想帮助公司建立自己的 wiki，完善的工程管理等等也都起到了作用，能得到一个平台的认可，或许是工作中最难得的东西。</p><p>半年之后公司业务定位也慢慢清晰起来，放弃了原来的创业项目，专注于众包服务。但是这个方向跟个人规划实在相差太大，工作陷入一种循环之中，越来越觉得无趣，跟技术组长也发生过一些很奇怪的争执。最终我跳到了今日头条，开始了第二家公司的职业生涯，这都是后话了。</p><p>从技能上来看，从出入职场时的半运维半后台到后台，再到前端。基本 web 的整个流程都有所覆盖，最后把个人突破点放在了前端上：这么选择是因为前端与用户接近，而且前端是计算机行业中与用户最接近的地方——或许也是最人文的地方。我一直认为技术哲学在互联网产业中能有所贡献，而且最容易结合起来的地方，就是前端。</p><h2 id="生活"><a href="#生活" class="headerlink" title="生活"></a>生活</h2><p>这一年中，从知春路搬到龙泽，又从龙泽搬回知春路，似乎完成了一个轮回。</p><p>在北京这样的城市生活，房租一直是个话题，就是一个字：贵。但是毕竟已经开始生活了，也不想像父辈那样在外打工时，随便租个老旧的房子凑合着过。于是就跑到龙泽那边跟朋友合租，并且视图打造老友记那种生活氛围。虽然事实证明这不太现实，但感觉还不错。</p><p>刚搬到出租房里的时候，用老家的一句话形容就是：干啥都摸不着气。不得不打电话咨询我妈，回答说是缺少必备的生活设备造成的，逐渐购置锅碗瓢盆，也亏得有个贤惠淑良的女朋友，慢慢的把房子收拾好了，开始有了生活的气息。</p><p>自己做菜，请朋友来家里聚餐这些活动在刚搬去的上半年也偶尔进行，但是下半年因为各种事情忙的焦头烂额，业余时间就懒多了，基本处于百废待兴状态。搬回知春路之后是一个较大的转折，不用每天去挤地铁坐公交，时间也宽裕了不少，又找回了生活的感觉。</p><h2 id="心理"><a href="#心理" class="headerlink" title="心理"></a>心理</h2><p>一年之中，心理上会产生许多变化，有一些学生时代的缺点慢慢被弥补了，同时也有很多优秀品质慢慢的消失了，比如每天花时间学习，出生牛犊不怕虎的气概。</p><h2 id="后记"><a href="#后记" class="headerlink" title="后记"></a>后记</h2><p>这篇文章写在六月毕业季，因为中间换了电脑，导致思路断断续续，直到现在也仍然是残缺的，但是随着在新公司的阅历增加，又慢慢找回了学习的状态，和当仁不让予师的感觉。对未来的职业生涯也有了更成熟一些的规划，继续补充中。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css&quot;&gt;&lt;h2 id=&quot;毕业一年&quot;&gt;&lt;a href=&quot;#毕业一年&quot; class=&quot;head</summary>
      
    
    
    
    <category term="随笔" scheme="https://xinghua.space/categories/%E9%9A%8F%E7%AC%94/"/>
    
    
  </entry>
  
  <entry>
    <title>常用算法</title>
    <link href="https://xinghua.space/2016/04/26/topological-sort/"/>
    <id>https://xinghua.space/2016/04/26/topological-sort/</id>
    <published>2016-04-26T08:22:21.000Z</published>
    <updated>2024-03-02T07:15:27.862Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css"><h2 id="拓扑排序"><a href="#拓扑排序" class="headerlink" title="拓扑排序"></a>拓扑排序</h2><p>刚听到「拓扑排序」这个概念的时候，我直接懵了，脑袋中过滤一遍，完全没有发现跟这个概念相关的知识。本科的时候学过图的算法，但主要集中于图的连通性，生成树，深搜，广搜等内容，似乎并没有什么「拓扑排序」。</p><p>当我了解到它的基本内容以及应用场景之后，才发现原来的确是有这个东西，只不过是没有明确的认识到这个概念和它的重要性。</p><h3 id="JavasCript-中的模块依赖关系"><a href="#JavasCript-中的模块依赖关系" class="headerlink" title="JavasCript 中的模块依赖关系"></a>JavasCript 中的模块依赖关系</h3><p>在写 JavaScript 的时候，我们应该都遇到过标题中的概念，比如有一个模块 A，它依赖于模块 B, C, D；模块 B 又依赖于 C, E, F；模块 C 依赖于 D, E, F, G。</p><p>换一种表示方式就是：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 模块：&#123;依赖模块&#125;</span></span><br><span class="line"><span class="attr">A</span>: &#123;B, C, D&#125;</span><br><span class="line"><span class="attr">B</span>: &#123;C, E &#125;</span><br><span class="line"><span class="attr">C</span>: &#123;D, E&#125;</span><br><span class="line"><span class="attr">D</span>: &#123;E&#125;</span><br><span class="line"><span class="attr">E</span>: &#123;&#125;</span><br></pre></td></tr></table></figure><p>如果要求用程序计算出存在依赖的模块系统中，每一个模块的依赖，最终输出的结果如图所示，那么该如何去考虑？</p><h3 id="直接遍历对应的图"><a href="#直接遍历对应的图" class="headerlink" title="直接遍历对应的图"></a>直接遍历对应的图</h3><p>很明显的一点是需要把模块依赖关系转换成图数据结构，在了解到拓扑排序的概念之前，我下意识的想法是图建立起来之后，直接选取一个点，比如 A 点，开始循环遍历，将 A 能到达的路径都加入进来，然和合并成一个 A 的依赖关系。可以用 dfs 或者 bfs 优化。</p><h3 id="拓扑排序-1"><a href="#拓扑排序-1" class="headerlink" title="拓扑排序"></a>拓扑排序</h3><p>直接参考<a href="https://songlee24.github.io/2015/05/07/topological-sorting/">拓扑排序（Topological Sorting）</a></p><h2 id="堆数据结构"><a href="#堆数据结构" class="headerlink" title="堆数据结构"></a>堆数据结构</h2>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css&quot;&gt;&lt;h2 id=&quot;拓扑排序&quot;&gt;&lt;a href=&quot;#拓扑排序&quot; class=&quot;head</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>什么是 Javascript Event Loop</title>
    <link href="https://xinghua.space/2016/04/26/javascript-event-loop/"/>
    <id>https://xinghua.space/2016/04/26/javascript-event-loop/</id>
    <published>2016-04-26T07:47:41.000Z</published>
    <updated>2024-03-02T07:11:18.164Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css"><p>本文为翻译文章，<a href="https://altitudelabs.com/blog/what-is-the-javascript-event-loop/">原文</a><sup id="fnref:1"><a href="#fn:1" rel="footnote"><span class="hint--top hint--error hint--medium hint--rounded hint--bounce" aria-label="2024 年，作者的博客已经无法再访问了，好在 Medium 上有一个备份：https://medium.com/@fay_jai/what-is-the-javascript-event-loop-98707ed20a90">[1]</span></a></sup></p><h2 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h2><p>如果你像我一样热爱 JavaScript。没错，它不是完美的语言，但是这个世界上哪有「完美的语言」这种存在？所以尽管 Javascript 有这样或那样的缺陷，我仍然喜欢 web 编程以及 JavaScript 给予我的编写连接这个世界的应用的能力。</p><p>但是 JavaScript 是有深度的——它有一个复杂的内部机制，你需要花费一定的时间去理解。其中一个有深度的地方就是 Event Loop。当然，即便是在对 JavaScript 的 Event Loop 没有精确理解的情况下，也能在很长时间内，正常使用 javascript 进行编程。然而，我希望本篇博客能带你走入 Event Loop 的世界，让你意识到这玩意儿并不是那么难以理解。</p><h2 id="浏览器中的-JavaScript"><a href="#浏览器中的-JavaScript" class="headerlink" title="浏览器中的 JavaScript"></a>浏览器中的 JavaScript</h2><p>当我们思考 JavaScript 的时候，我们通常会默认一个语境前提——web 浏览器——这使得大多数人都是在客户端编写 JavaScript 代码。事实上，意识到运行任何 web 应用实际上包含一些列技术，像 JavasCript 引擎（如 Chrome 的 V8 引擎），一堆 Web API（如 DOM），还有时间轮询（Event Loop）和事件队列（Event Queue）。</p><p>看到上面这些内容之后，你可能会想：『艹，这下看起来更复杂了…』——或许的确是这样——但是你很快就会看到，上面这些技术的核心思想真的没有那么复杂，甚至你可能发现，实现它们会非常容易。</p><p>在深入研究 event loop 之前，我们需要对 JavaScript 引擎和它的工作原理有一些基本的理解。</p><h2 id="JavaScript-引擎"><a href="#JavaScript-引擎" class="headerlink" title="JavaScript 引擎"></a>JavaScript 引擎</h2><p>目前不同的 JavaScript 引擎实现有好几种，但是当前最流行的实现版本是 Google Chrome 的 V8 引擎（这个引擎不受限于浏览器端，在服务器端的 Nodejs 使用的也是它）。说了这么多，那 JavaScript 引擎到底是干啥的？其实很简单——它的工作就是遍历 Web 应用中的每一行 JavaScript 代码，并且逐个执行（process one at a time）。你没有看错——就是逐个执行，这意味着 JavaScript 是单线程的。这一特点的主要影响是，如果你执行一行需要非常非常长的时间才能返回结果的代码，这之后的代码都会被阻塞掉。我们当然不想写出这么阻塞的代码——特别是在浏览器中。想象一下你正在查看一个 Web 网页并且垫底了某个按钮…它就这么耗在了那里。你试着点击其他的按钮，然而并没有什么卵用，啥作用都没起。这种蛋疼的局面只能归罪于点击按钮的时候触发了某些代码的执行（假设没有 bug 的话），但是这些代码阻塞在了那里。</p><p>另一方面，JavaScript 引擎如何知道一次只执行一行代码的？它使用了一个调用栈（call stack）。你可以把调用栈想象成一个叠罗汉活动——第一个叠罗汉的只能最后一个下来，对应的是最后一个叠罗汉的第一个下来（原文用乘电梯作比喻，个人认为不是很形象，改成了叠罗汉）。</p><p>下面来看一个例子：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Within main.js */</span></span><br><span class="line"><span class="keyword">var</span> firstFunction = <span class="keyword">function</span> (<span class="params"></span>) &#123;  </span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;I&#x27;m first!&quot;</span>);</span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">var</span> secondFunction = <span class="keyword">function</span> (<span class="params"></span>) &#123;  </span><br><span class="line">  <span class="title function_">firstFunction</span>();</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;I&#x27;m second!&quot;</span>);</span><br><span class="line">&#125;;</span><br><span class="line"><span class="title function_">secondFunction</span>();</span><br><span class="line"><span class="comment">/* Results:</span></span><br><span class="line"><span class="comment"> * =&gt; I&#x27;m first!</span></span><br><span class="line"><span class="comment"> * =&gt; I&#x27;m second!</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure><p>下面是执行代码中，调用栈中发生的一系列事件：</p><ol><li><p>Main.js 首先被执行<br><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.1evqqj6whq2o.webp" alt="初始状态"></p></li><li><p>secondFunction 被调用</p></li></ol><p>#<a href="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.157h49iavv34.webp">secondFunction 被调用之后</a></p><ol start="3"><li><p>调用 secondFunction 的时候，内部函数 firstFunction 也被调用：<br><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.6v22n4e2e400.webp" alt="firstFunction 被调用之后"></p></li><li><p>执行 firstFunction 的时候，会输出”I’m first!”,并且由于在 firstFunction 中，没有其他代码要执行，整个 firstFunction 的执行到此结束，被移出调用栈：<br><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.2ehg5fnit9jw.webp" alt="当 firstFunction 返回之后"></p></li><li><p>firstFunction 执行结束返回之后，secondFunction 继续执行，输出”I’m second!”。一旦输出完毕之后，secondFunction 函数中，也没有其他代码要执行，整个 secondFunction 函数执行完毕，被移出调用栈：<br><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.4i4gxzrtf400.webp" alt="当 secondFunction 返回之后"></p></li><li><p>最后，由于 main.js 中没有其他代码要执行，main.js 也被移出调用栈：<br><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.4ga09okx9j40.webp" alt="当 main.js 返回之后"></p></li></ol><h2 id="OK，但是这根-Event-Loop-有毛线关系？"><a href="#OK，但是这根-Event-Loop-有毛线关系？" class="headerlink" title="OK，但是这根 Event Loop 有毛线关系？"></a>OK，但是这根 Event Loop 有毛线关系？</h2><p>现在你已经明白 JavaScript 引擎中的调用栈是如何工作的了，让我们回到之前的代码阻塞的思路上来。当然，你已经意识到应该避免出现这些阻塞，但是该怎么做？幸运的是，JavaScript 提供了一种机制，它基于异步回调函数（asynchronous callback function）的方式来实现。这个概念看起来有些吓人，不过不用担心——所谓异步函数和你在 JavaScript 中使用的普通函数没有什么两样，只不过是加了一些它会在之后执行（而不是立即）执行的手段。如果你使用过 Javascript 的 setTimeout 函数，你其实已经使用过异步回调函数的概念了。下面来看一个例子：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Within main.js */</span></span><br><span class="line"><span class="keyword">var</span> firstFunction = <span class="keyword">function</span> (<span class="params"></span>) &#123;  </span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;I&#x27;m first!&quot;</span>);</span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">var</span> secondFunction = <span class="keyword">function</span> (<span class="params"></span>) &#123;  </span><br><span class="line"> <span class="built_in">setTimeout</span>(firstFunction, <span class="number">5000</span>);</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;I&#x27;m second!&quot;</span>);</span><br><span class="line">&#125;;</span><br><span class="line"><span class="title function_">secondFunction</span>();</span><br><span class="line"><span class="comment">/* Results:</span></span><br><span class="line"><span class="comment"> * =&gt; I&#x27;m second!</span></span><br><span class="line"><span class="comment"> * (And 5 seconds later)</span></span><br><span class="line"><span class="comment"> * =&gt; I&#x27;m first!</span></span><br><span class="line"><span class="comment"> */</span></span><br></pre></td></tr></table></figure><p>下面是调用栈中的一系列活动（我们省去了前面的函数加入调用栈的过程，直接来看 setTimeout 函数）：</p><ol><li>当 secondFunction 被推入调用栈之后，setTimeout 函数被调用，而且也被压入调用栈中：<br><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.59jdii43mas0.webp" alt="在 setTimeout 函数执行之前"></li></ol><p>当 setTimeout 函数被执行的时候，发生了一些比较特殊的事——浏览器把 setTimeout 的回调函数（在本例中是 firstFunction）存入一个 Event Table 中。可以将 Event Table 想象成一个电话注册本：调用栈会告诉 event table 注册一些特定的函数，并且在指定事件发生时会调用他们。当这些指定事件发生时，event table 仅仅是简单地把要调用的函数移入 Event Queue 中去。event queue 的美妙之处在于它提供了一个简单等待区域，函数在此区域内等待被移入调用栈进行调用。<br>你或许会问：『究竟什么情况下，event queue 中的函数才会被移入调用栈中？』。实际上，JavaScript 遵从一个简单的法则：存在一个监控进程不断检查调用栈是否为空，当调用栈为空的时候，检查事件队列（event queue）中是否有待调用的函数。如果事件队列中存在待调用的函数，队列头部的函数被移入调用栈执行。如果事件队列为空，监控进程就保持轮询状态。</p><p>瞧，我刚才描述的内容就是臭名昭著的 Event Loop（事件轮询）了！</p><ol start="2"><li><p>现在回到我们之前的 setTimeout 的例子。执行 setTimeout 函数的过程中，引擎将它的回调函数（在本例中为 firstFunction）添加到 event table 中，同时注册触发事件为 5 秒延迟。<br><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.5nzgn34nn8k0.webp" alt="当 setTimeout 函数被执行之后"></p></li><li><p>下面是另一个让你觉得「啊哈，是这样！」的时刻——注意到一旦回调函数被移入 event table 之后，没有代码在阻塞了！浏览器在执行后面的任何代码之前，并不会在那里傻等 5 秒了——它直接执行 secondFunction 函数中 setTimeout 函数后面的代码，在这里是 console.log 语句。<br><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.4ahr7wpq7j80.webp" alt="secondFunction 执行完毕之后"></p></li><li><p>在后台，event table 一直监控是否有指定的事件发生，如果有将触发把对应的函数移入事件队列（event queque）的动作。在上面的例子中，secondFunction 到这里已经执行完毕，于此同时 main.js 到这里也执行完成了。<br><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.2chkily7e1wk.webp" alt="当 main.js 执行完成之后"></p></li><li><p>大约算来，在回调函数放入 event table 后 5 秒钟，event table 会把 firstFunction 移入事件队列中。<br><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.27kc1s3tmn6s.webp" alt="main.js 执行结束后约 5 秒钟"></p></li><li><p>由于事件循环不断监视调用堆栈是否为空，因此它现在注意到调用堆栈确实为空，并调用 firstFunction 创建一个新的调用堆栈。<br><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.27kc1s3tmn6s.webp" alt="新的调用栈"></p></li><li><p>一旦 firstFunction 执行完毕之后，我们会回到调用栈为空的状态，这个时候 event table，event queue 也都为空。<br><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.31bivw5r6yo0.webp" alt="当 firstFunction 执行完毕之后"></p></li></ol><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>我承认我上面的解释掩盖了 JavaScript 引擎中，以及 event table，event queue 和 event loop 中非常多的实际实现细节。但是，对于大部分人来说，我们仅仅需要对 JavaScript 执行异步函数时发生的事情有一个笼统的认识。我希望上面的解释能帮助你明晰背后的机制，并且满足平常的 web 开发工作。</p><h2 id="扩展问题"><a href="#扩展问题" class="headerlink" title="扩展问题"></a>扩展问题</h2><p>问题：setTimeout 中设置的时间是准确的吗？<div id="footnotes"><hr><div id="footnotelist"><ol style="list-style: none; padding-left: 0; margin-left: 40px"><li id="fn:1"><span style="display: inline-block; vertical-align: top; padding-right: 10px; margin-left: -40px">1.</span><span style="display: inline-block; vertical-align: top; margin-left: 10px;">2024 年，作者的博客已经无法再访问了，好在 Medium 上有一个备份：<a href="https://medium.com/@fay_jai/what-is-the-javascript-event-loop-98707ed20a90">https://medium.com/@fay_jai/what-is-the-javascript-event-loop-98707ed20a90</a><a href="#fnref:1" rev="footnote"> ↩</a></span></li></ol></div></div></p>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css&quot;&gt;&lt;p&gt;本文为翻译文章，&lt;a href=&quot;https://altitudelabs.</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>板砖，石头与 Web 标准，W3C</title>
    <link href="https://xinghua.space/2016/04/20/standardization/"/>
    <id>https://xinghua.space/2016/04/20/standardization/</id>
    <published>2016-04-20T07:41:51.000Z</published>
    <updated>2024-03-02T07:15:09.643Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css"><h2 id="砖头与石头"><a href="#砖头与石头" class="headerlink" title="砖头与石头"></a>砖头与石头</h2><p>板砖这种神器，大街小巷，犄角疙瘩，几乎只要有人居住的地方就可以看到它的存在。<br>当然石头虽然不像砖头那样随处可见，但是也地位不凡，各种建筑材料，雕塑，石碑等等也都能见到它的身影。</p><p>如果对于板砖与石头这两种寻常不过的事物，我问它们的差别是什么，可能有人会发笑，板砖与石头简直风马牛不相及，除了组成成分有某些交集，都在建筑上有一些应用之外，其他几乎毫无共同点，至于讨论它们的差别，似乎更是毫无意义。</p><p>当然上面答案是没什么大问题的，但它并不是一个好的思路或者说看待问题的视角，下面我们来看看从一个特定角度来看看砖头和石头有何区别。</p><h2 id="有什么区别"><a href="#有什么区别" class="headerlink" title="有什么区别"></a>有什么区别</h2><p>第一个区别：<strong>板砖是人造的，石头是天然的</strong></p><p>乍一看这个区别，似乎没啥大毛病，但似乎也没什么让人「哦，就是这样」的感觉。我们会往下追问，然后呢，这又咋地？</p><p>第二个区别：<strong>板砖符合特定的规格，石头则基本无定形</strong></p><p>板砖既然是人造的，那肯定要合乎某种预设目的。砖头用来建造房子，而未经加工的天然石头形状奇奇怪怪，在建筑上不堪大用，但这个区别似乎也是正确的废话。</p><p>那再来看第三个区别：<strong>板砖是工业标准化的体现，石头则是自然的无序体现</strong></p><p>这似乎有点意思了，因为顺着这个思路一看，我们能发现很多东西，那就是板砖不再是板砖本身，它还是工业化进程上的一部分。正是这种工业标准化，让砖头可以更容易，更经济的生产出来，以及组织起来，并且更好的服务于工业本身。</p><p>小小的一块板砖，基本上浓缩了工业的最重要的特质。对比来看石头，各种无规则的形状，也就是凑合着垒个墙什么的，如果你想让石头发挥更大的作用，那还得像砖头那样去处理它，让它更容易的与周围的环境交互。</p><p>因此从上述视角来看，虽然板砖与石头自身有一些差别，但更大的差别不是在它们自身，而是把他们放在群体之中时，所体现出的差别。</p><h2 id="这又如何呢"><a href="#这又如何呢" class="headerlink" title="这又如何呢"></a>这又如何呢</h2><p>可能你认为上边说的没错，但这又说明啥呢，它似乎并不能对我们的生活产生什么影响，我们或许说不清楚板砖和石头的区别，但我们已经按照正确的方式使用它们了。</p><p>当然板砖和石头的差别，即使深入追究也非常有趣，但更有趣的是它们之间的差别蕴含的工业标准化与非标准化之间的差别。这种「工业标准化」的思路，已经在工业时代之后随处可见了——符合特定规则的内存，硬盘，机箱，可以让我们很容易的组装起一台个人计算机。如果你开车去国外旅游，车轱辘掉了或者螺丝掉了，都可以随时再买上一打，而不需要从自己国家去取。对比来说，你可以设想一下非标准化时的场景下，如果你在自己家乡定制了一辆车，开出去之后半路坏掉的话，会遇到怎样尴尬的场景。</p><p>事实上，所有的工业标准化，其意义都是相似的：一些标准化让事物更好的融入群体之中，一些标准化让事物超越空间，时间和特定的人得以存在。</p><p>所谓融入群体，就如上面的板砖；所谓超越空间时间存在，是指不同区域，不同时间的人，都能约定俗称的使用同一种规格，而不必担心它们的兼容性；所谓超越特定的人存在，也就是标准化之后的事物，它们的制作工艺，他们的维护，再生产，不必依赖于某一个特定的人或者群体，麦当劳和中国菜就是很好的例子，中国菜依赖于个人经验，难以量化和标准化，如果某些大厨挂了，那很可能就再也吃不到与他做的同样好吃的菜式了。但是麦当劳不同，只要有量化的配方以及标准化的生产，谁跪了似乎都无所谓。</p><p>标准化如此常见，以至于它变得透明起来，消失在我们的视野中，成为一种「消失的存在」。</p><h2 id="Web-标准"><a href="#Web-标准" class="headerlink" title="Web 标准"></a>Web 标准</h2><p>最近又看到一个经典的前端面试题：「你是如何理解 web 标准以及 W3C 的」，其实这个问题的思路跟上面基本是一致的：工业标准化能带来什么，Web 标准化就能带来什么。</p><p>关于 web 标准的细节，这里不做讨论。Web 标准当然很好，它为内容，表现，行为提供了良好的可实践标准，并且可以据此建立起高可用，易理解，适应性强的 web 系统结构。</p><h2 id="W3C"><a href="#W3C" class="headerlink" title="W3C"></a>W3C</h2><p>标准的意义是在标准被普及，被遵守后体现出来的。遵守的人越多，产生的好处越大，最终建立一个运行在互联网上的一个个标准的 Web 系统。由于每一个 Web 系统都是标准的，那它们不仅对于人类是友好的，对于各种处理这些 Web 系统的更高层的系统（比如说搜索引擎）也将是友好的。</p><p>关于互联网有一个经验公式，互联网的价值和组成它的节点数量的平方成正比。对于 Web 标准化也是类似的。根据 Web 标准本身可以建立起一个个结构清晰的 web 系统，而这些标准的 web 系统又联合起来组成一个更大的标准系统，这就使得各类工作更容易进行，以及在此基础上做更多的事情，产生更大的价值。这个时候就类似于之前说的板砖，或者更早博客中提到的集装箱了。</p><p>Web 标准的自身的意义并不是最重要的，很可能存在比当前 web 标准更好的标准。一个易于普及的良好定义的标准，比一个更优秀的但是难以普及的标准，可以产生更大的价值。类似的例子再历史上比比皆是。</p><p>至于 W3C（万维网协会），则是 Web 标准化进程的领头羊，负责制定，推广 Web 标准，不仅要保证当前标准自身是好的，还要协调不同的厂商，让标准是更容易接受，普及的，可谓任重道远。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css&quot;&gt;&lt;h2 id=&quot;砖头与石头&quot;&gt;&lt;a href=&quot;#砖头与石头&quot; class=&quot;he</summary>
      
    
    
    
    <category term="作为工程师" scheme="https://xinghua.space/categories/%E4%BD%9C%E4%B8%BA%E5%B7%A5%E7%A8%8B%E5%B8%88/"/>
    
    
  </entry>
  
  <entry>
    <title>钟楼和时间革命</title>
    <link href="https://xinghua.space/2016/04/09/horologe-in-church/"/>
    <id>https://xinghua.space/2016/04/09/horologe-in-church/</id>
    <published>2016-04-09T07:36:23.000Z</published>
    <updated>2024-03-02T07:10:52.551Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css"><blockquote><p>现代工业时代的关键不是蒸汽机，而是时钟。——刘易斯·芒福德</p></blockquote><h2 id="击溃牛顿的钟表匠"><a href="#击溃牛顿的钟表匠" class="headerlink" title="击溃牛顿的钟表匠"></a>击溃牛顿的钟表匠</h2><p>曾经无意中看到罗辑思维中有一期节目叫《击溃牛顿的钟表匠》。主要讲述了一位钟表匠制造出高精度的钟表，使得航海事业中准确定位成为可能，极大的促进了航海事业的发展。</p><p>实际上，关于钟表的故事不仅仅是这些。定位经度，促进航海事业的发展固然是人类历史上的大事，但是相比于钟表在公元 10 世纪~20 世纪所起的作用来说，仍然只是冰山一角。只不过因为钟表所造成的其他影响，对于我们而言几乎是「透明的」。在技术哲学发展之后，才慢慢揭开它的神秘面纱。</p><p>本文就从钟楼建筑开始，来简单介绍一下时间的代言人——钟表还有其他哪些故事。</p><h2 id="随处可见的钟楼"><a href="#随处可见的钟楼" class="headerlink" title="随处可见的钟楼"></a>随处可见的钟楼</h2><p>直到今天，我们仍然可以在一些比较古老的大城市看到钟楼，大学和教堂里一直矗立着它们的身影。甚至在一些新兴的城市里，也都会在一些关键的地方立起一座钟楼，随时提醒人们现在的时间。</p><p>钟楼是一种公共的计时工具，它在 13 世纪末~14 世纪初前后出现，并且迅速成为教堂，大学中的必备建筑。在寺院或者大学中，要求人们严格按照时间来安排自己的日常活动，比如寺院中的祈祷，礼拜，用餐等活动都有着严格的规律与秩序。</p><p>事实上，如果说钟楼这种产物是人类聚集成城市，有了安排生活，协调活动需求的产物的话。早在钟楼出现之前的公元 10 世纪前后，寺院就已经具备了一些计时工具。相传 10 世纪末的一名叫戈伯特（Gerbert）的僧侣就发明了机械水钟。因为规律，秩序，守时这些生活要求，几乎是教堂寺院的天然生活要求，并且随着时间的发展不断强化。（参考刘易斯·芒福德《技术与文明》）</p><p>机械钟楼的出现，使得计时工具不在受到自然天气状况的影响。水流会结冰，日月星辰会被掩盖，机械钟则完全没有这些缺点，可以较为可靠的运行在各种自然状况下。于是很快被教堂寺院，以及后来出现的大学采用。</p><p>钟楼的意义和钟楼的消失<br>如前文所述，钟楼是一种公共的计时工具，它天生就带有自己的规范——规律、秩序、守时、将看不见摸不着的时间量化。</p><p>钟楼可以大范围的协调，约束人类的生产和生活。使各类活动有秩序的进行。在教堂寺院中，可能所带来的影响就是严格的祈祷，礼拜，产生一种宗教意义上的行为规范。但出了教堂，到了城市中之后，这种守时，秩序的钟表规范。协调了人类的生产活动，将时间观念逐渐带入人类世界。</p><p>这种时间观念一是会提高人类生产活动的效率（在「效率的概念」产生之前，「效率」本身就已经开始存在，并且被有意识或无意识的加强了），这同时也会反过来继续促进钟表事业的发展。</p><p>像钟楼这种重型的计时工具，一般在一大片区域内才有一座，并不是十分方便。而制种工艺的不断改善尤其是 15 世纪的发条发明之后，钟表的小型化开始有了技术基础，并且体积随之开始减小，小式的座钟开始进入房屋之中。随着制钟工艺的愈加精确以及成本的降低，这种计时工具开始走向普及。</p><h2 id="时间革命"><a href="#时间革命" class="headerlink" title="时间革命"></a>时间革命</h2><p>有一些历史研究者认为，在工业革命之前的几个世纪中，其实已经悄然进行着另一场革命，也就是所谓的「时间观念革命」或者叫「效率革命」。正是这场革命造成的变化，成为了工业革命的基石。</p><p>时间革命的发源，基本上可以从钟表彻底融入人类生活开始。当人们开始摆脱原始的「相对时间观念」，也即摆脱那种全靠日月星辰，季节变换来感知时间变换的手段，进而采用一种人造的，机械的手段来计时时，时间革命就开始了。时间不再是事物的发展变换，而是独立出来，成为了一种可以衡量量化的东西。</p><p>人们开始按照钟表给时间划分刻度，而且越来越精确。时分秒这些时间单位的引进，让人们清晰的感受到「时间」的流逝，以及时间在日常生活，商业活动中所起到的重要作用。随着商业的发展，在一定的时间内产生更多的资源成为了一种绝对的追求。这个时候，「效率」的思想已经有了萌芽。</p><p>人们不断通过各种手段来提高效率，改进生产流程，改革生产管理，采用新技术等等。正是在这样的环境下，工业革命有了发芽的土壤。</p><h2 id="时间就是金钱"><a href="#时间就是金钱" class="headerlink" title="时间就是金钱"></a>时间就是金钱</h2><p>到了今天，「时间就是金钱」已经成为一个口头隐喻了。在我们的文化中，时间已经成为了一种宝贵的商品，是我们达成目标所需的有限资源。人们按小时，星期来计算薪酬，更精确的按照分钟来计算话费等等。我们已经把许多金钱方面的词汇概念用于时间的表达上，时间成了一种可以花费，浪费，预算，投资，节省或挥霍的东西。总而言之，时间的观念重新构建了我们日常基本生活中的行为以及对这个世界的认知。</p><p>这一切的一切都是从钟楼等这类人造的，独立于自然因素的计时工具开始的。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css&quot;&gt;&lt;blockquote&gt;
&lt;p&gt;现代工业时代的关键不是蒸汽机，而是时钟。——刘易斯</summary>
      
    
    
    
    <category term="科哲和科学史" scheme="https://xinghua.space/categories/%E7%A7%91%E5%93%B2%E5%92%8C%E7%A7%91%E5%AD%A6%E5%8F%B2/"/>
    
    
  </entry>
  
  <entry>
    <title>关于圆锥曲线光学性质的有趣解释 (证明与原因)</title>
    <link href="https://xinghua.space/2016/04/04/somethings-about-ellipse/"/>
    <id>https://xinghua.space/2016/04/04/somethings-about-ellipse/</id>
    <published>2016-04-04T07:24:12.000Z</published>
    <updated>2024-03-02T07:14:57.617Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css"><p>突然想起很久之前，在其他地方贴过一个关于椭圆光学性质的文章。直到今天想来，这个解释仍然是十分直观和有趣。当时我以为这样一个解释方式是「本质的」，但经同学提醒，用「直观」这个词或许会更准确。</p><p>虽然文章说的是椭圆，但是放在更一般的圆锥曲线上基本上也都适用。</p><h2 id="椭圆的光学性质"><a href="#椭圆的光学性质" class="headerlink" title="椭圆的光学性质"></a>椭圆的光学性质</h2><p>在圆锥曲线的性质中，我们常常会见到下面这样一张图：从椭圆的一个焦点入射的光线，经过椭圆壁的反射后，会通过另一个焦点。</p><p><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.2w7eaer55vo0.webp" alt="椭圆的光学性质"></p><p>当然在其他一些圆锥曲线，比如抛物线或是双曲线中，也会有一些类似的性质，大抵都是从焦点发出的光线怎样怎样等。</p><p>但是为什么？</p><p>显然，可以通过数学来证明这一点，即反射处（图为 P 点）的入射光线和出射光线，与该点处的切线夹角相等。证明过程这里省略，虽然有些曲折，但是也不算是难以理解的问题。</p><p>问题在于，我通过一堆数学证明结果后，仍然对此答案感到不满意。对于我来说，这种数学证明只是相当于将问题向数学方向上退了一步，把原问题换成了数学描述而已。我仍然可以继续追问下去：为什么这么巧合，入射角和反射角经过数学计算后正好相等？</p><p>我想知道的是「为什么椭圆会有这样的特质」，而不是「证明椭圆有这样的特质」。正如王垠在原因与证明里说的那样。其实这里想表达的还是「直推因」和「目的因」的区别。</p><p>那么我不通过这么复杂的证明能否提前预知到这一点？</p><h2 id="一个更有趣的解释-力学性质"><a href="#一个更有趣的解释-力学性质" class="headerlink" title="一个更有趣的解释 (力学性质)"></a>一个更有趣的解释 (力学性质)</h2><p>纠结于这个问题以及椭圆的这些奇妙性质，高中的时候我想了好久。</p><p>突然有一天我注意到了数学课本上椭圆的画法：将绳子固定在两颗钉子上，用笔尖把绳子拉紧，绕钉子一周，则得到一个椭圆。</p><p><img src="https://cdn.jsdelivr.net/gh/starding/picx-images-hosting@master/20240224/image.2hd4q2vcybg0.webp" alt="椭圆的画法"></p><p>仔细想发现这个描述很有意思，它具有了两个隐含的事实：</p><p>第一个内容很明显，也算是椭圆的定义：椭圆上任意一点到两焦点的距离之和恒定。</p><p>第二个内容则比较隐蔽，可以从物理学角度来分析这个画椭圆的过程：在画椭圆的时候，对于任何一个切线点，笔尖两端的力是相等的，那么必然有入射角等于反射角这个性质，不然绳子不会平衡（而是会滑动）。由此可以预想到，计算的结果也会是这样。</p><p>至此，“为什么”的问题才算有了个“直观上的”解释。</p><h2 id="其他一些有趣的推广"><a href="#其他一些有趣的推广" class="headerlink" title="其他一些有趣的推广"></a>其他一些有趣的推广</h2><p>上面的思路可以推广到圆锥曲线中去，即便对于椭圆本身也有一些扩展，比如两颗钉子的距离调整，比如当两颗钉子重合的时候会如何？答案是显而易见的。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css&quot;&gt;&lt;p&gt;突然想起很久之前，在其他地方贴过一个关于椭圆光学性质的文章。直到今天想来，这</summary>
      
    
    
    
    <category term="随笔" scheme="https://xinghua.space/categories/%E9%9A%8F%E7%AC%94/"/>
    
    
  </entry>
  
  <entry>
    <title>什么是模态框（modal dialog）</title>
    <link href="https://xinghua.space/2016/03/19/model-dialog/"/>
    <id>https://xinghua.space/2016/03/19/model-dialog/</id>
    <published>2016-03-19T07:13:33.000Z</published>
    <updated>2024-03-02T07:12:44.087Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css"><h2 id="问题来源"><a href="#问题来源" class="headerlink" title="问题来源"></a>问题来源</h2><p>在学习前端的时候，我遇到一个让人费解的词：「模态框」，它对应一种特殊的弹出式窗口。而且一时之间很难说清楚到底特殊在什么地方，以及这样的弹窗与其他类型窗体的核心区别在哪里。与「对话框」，「面板」这些比较直白的词汇不同，「模态」这个词处处透漏着一种玄乎的感觉，很难直观的感受到它到底是个啥，又想要通过这个词来表达什么，你会不自觉的感到困惑：啥叫模态？</p><p>在计算机领域的词汇中，我一直抱有这样一种信念：如果一个词汇显得玄乎，那它背后肯定隐藏着更多的东西，或许是某些隐喻，或许是一些更深层次的设计原理等等。无论如何，都值得去好好调查一番这些词汇背后的含义，可能这些小小的词汇就成了通往一个个饶有趣味的世界的门径。</p><h2 id="什么是「模态」？"><a href="#什么是「模态」？" class="headerlink" title="什么是「模态」？"></a>什么是「模态」？</h2><p>要理解模态框的含义，除了先用眼睛看看这个词汇对应的东西到底是个啥（可以找 bootstrap 的模态框组件体验）之外，最应该干的事情，就是先搞明白「模态」的含义了。</p><p><strong>模态，英文词汇叫 modal</strong></p><p>先看看「模态」的字典解释：模式的，情态的，形式的。</p><p>再看看使用这个词汇组合出来的一些让人莫名其妙的专业词汇。</p><ul><li>模态分析</li><li>模态矩阵</li><li>模态逻辑</li><li>模态框</li></ul><p>我们可以猜想一下这个词汇的引入情景，或者说从英文词汇 modal 翻译成汉语的情形：想要表达一种特定状态下的内容，那该怎么翻译比较好呢？我们知道「模型」这个词有「一种事物的固定抽象」的含义，那么它可以表达一种「固定模式的含义」，而「状态」一词，可以表示事物在某种情形下的表现。这两者结合一下，「模态」这个词便呼之欲出了。当然，实际的翻译和词汇创造肯定远远比上面描述的情况复杂，但核心思想是一致的，也即：如何信达雅的表示出一个事物的概念。</p><p>经过这样的分析，我们可以说算是对「模态」这个词稍有了解了，它指的是<strong>某种特定的状态</strong>。</p><p>这个时候再来看看上面那些专业词汇，就比较容易理解了，也就是说他们都有一种<strong>「研究某些特定状态下的事物」</strong>的意思。</p><h2 id="什么是「模态框」"><a href="#什么是「模态框」" class="headerlink" title="什么是「模态框」"></a>什么是「模态框」</h2><p>有了上面的词汇理解基础，我们可以继续往下说模态框的概念了。从字面意思上来看，它指的应当是「某种特定状态下的窗体」。</p><p>当然，仅仅这样来看，可能仍然有些难以理解。这是因为我们缺了另外一些东西造成的，缺少的就是「模态框」这个东西使用的语境，只有加入这些内容才能让我们的理解完整。</p><p>那么模态框使用的语境是什么？当然，这个词是在软件领域产生的，我们可以先看看普通的软件使用流程。在使用软件的时候，我们一般都会按照自己的思路一步步操作，比如我们在使用一个购物系统，我们会按照我们对这个软件的固有理解来执行自己脑中的流程：选购商品，加入购物车，下单付款等等。这些流程可以说是我们使用软件时的一种「正常状态」。</p><p>「模态框」这种『特定状态下的窗体』正是相对于上面叙述的这种「正常状态」来说的。模态框是出于一种特定状态下的窗体，它会把我们从正常状态中中断出来，将关注点放在这个特定状态的处理上。可以看看模态框的实际表现：当模态框出现的时候，它会屏蔽掉所有其他操作，用户可关注的范围只限于当前的模态框内部，除非你特意去关闭这个模态框，结束这种中断，回到原先正常的流程中去。</p><p>上面所描述的就是模态框的核心思想。其实准确地说，模态框是一个 UI 设计领域的概念，维基百科的定义是：</p><blockquote><p><strong>model window</strong></p><p>In user interface design, a modal window is a graphical control element subordinate to an application’s main window which creates a mode where the main window can’t be used. The modal window is a child window that requires users to interact with it before it can return to operating the parent application, thus preventing the workflow on the application main window. Modal windows are often called heavy windows or modal dialogs because the window is often used to display a dialog box.</p><p>Modal windows are commonly used in GUI systems to command user awareness and to display emergency states, although they have been argued to be ineffective for that use. Modal windows are prone to produce mode errors.</p></blockquote><p>当然模态框这种设计理念，暗含着一种强制性的思路。它强制用户的关注点从正常思维流中抽出来，来关注模态框内的内容，有些强制思考的意味。这种设计理念一般用在比较危险的操作的提示上。</p><p>但是对模态框的批评也是多种多样，主要是批评这种强制性的设计思路，以及它是否应被更好的方案代替等等，更有些观点宣称模态框是「邪恶的」。关于这些批评，可以参考下面一些资料：</p><ul><li><a href="https://stackoverflow.com/questions/361493/why-are-modal-dialog-boxes-evil">Why are modal dialog boxes evil?</a></li><li><a href="https://alistapart.com/article/neveruseawarning/">Never Use a Warning When you Mean Undo</a></li></ul><h2 id="「非模态」"><a href="#「非模态」" class="headerlink" title="「非模态」"></a>「非模态」</h2><p>有模态的概念，当然也有非模态的概念，关于非模态概念，本文暂时按下不表。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css&quot;&gt;&lt;h2 id=&quot;问题来源&quot;&gt;&lt;a href=&quot;#问题来源&quot; class=&quot;head</summary>
      
    
    
    
    <category term="作为工程师" scheme="https://xinghua.space/categories/%E4%BD%9C%E4%B8%BA%E5%B7%A5%E7%A8%8B%E5%B8%88/"/>
    
    
  </entry>
  
  <entry>
    <title>html5 设计原理</title>
    <link href="https://xinghua.space/2016/03/19/html5-design-principle/"/>
    <id>https://xinghua.space/2016/03/19/html5-design-principle/</id>
    <published>2016-03-19T02:30:47.000Z</published>
    <updated>2024-03-02T07:11:04.020Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css"><p>之所以取个这么大的标题，是因为这是一篇翻译稿的标题。个人认为这篇演讲的翻译稿非常符合我的思维习惯，而且网上没有一个比较好的版本，故单读整理出来，形成一篇转载文章。</p><p>前一段时间，我们小组一直有一个争论，就是在 api 中到底是使用 utc 时间，还是使用 unix 时间戳。个人坚持的观点就是「先为人设计，再为机器设计」，赞同语义化更强的 utc 时间。</p><p>上面的例子是想说明，有时候我们做出一件决策，不能仅仅根据根据一时的想法，想当然的认为某些事情应该怎样，而应该遵循一些明显经过时间检验的设计原则行事。尤其是遇到一些两难的选择时，遵循一些这个领域的原则，可能会带来意象不到的好处。</p><p>同样，我们在关注一件新事物，比如 html5 时（其实不算新了），不能只是看它出现了那些新元素，新 api 等等。而是应该考虑这背后的一些设计理念以及发展历程，它解决了什么痛点，如此我们才能更好的把握这些事物从哪里来，未来会怎样等问题的脉络。</p><br/><hr><h2 id="HTML5-设计原理"><a href="#HTML5-设计原理" class="headerlink" title="HTML5 设计原理"></a>HTML5 设计原理</h2><p>2010 年 10 月 21 日 <a href="http://adactio.com/articles/1704/">Jeremy Keith 在 Fronteers 2010 上的主题演讲</a></p><p><a href="http://www.cn-cuckoo.com/category/web">Web 开发翻译</a> <sup id="fnref:1"><a href="#fn:1" rel="footnote"><span class="hint--top hint--error hint--medium hint--rounded hint--bounce" aria-label="不清楚博主的这篇翻译文章为什么没了，但原翻译者应该是他没错，这里只进行一下整理">[1]</span></a></sup></p><p>今天我想跟大家谈一谈 HTML5 的设计。主要分两个方面：一方面，当然了，就是 HTML5。我可以站在这儿只讲 HTML5，但我并不打算这样做，因为如果你想了解 HTML5 的话，你可以 Google，可以看书，甚至可以看规范。</p><p>实际上，确实有人会谈到规范的内容。史蒂夫·福克纳（Steve Faulkner）会讲 HTML5 与可访问性。而保罗·艾里什（Paul Irish）则会讲 HTML5 提供的各种 API。因此，我今天站在这里，不会光讲一讲 HTML5 就算完事了。</p><p>说老实话，在正式开始之前，我想先交待清楚我所说的 HTML5 到底是什么意思。这话听起来有点搞笑：这会子你一直在说 HTML5，难道我们还不知道什么是 HTML5 吗？大家知道，有一个规范，它的名字叫 HTML5。我所说的 HTML5，指的就是这个规范。但问题是，有些人所说的 HTML5，指的不仅仅是这个规范，还有别的意思。比如说，用 HTML5 来代指 CSS3 就是一种常见的叫法。我可不是这样的。我所说的 HTML5，不包含 CSS3，就是 HTML5。</p><p>类似的术语问题以前也有过。Ajax 本来是一种含义明确的技术，但过了不久，它的含义就变成了“用 JavaScript 来做一切好玩的东西”。这就是 Ajax，对不对？今天，HTML5 也面临同样的问题，它本来指的是一个特定的规范，但如今含义却成了“在 Web 上做一切好玩的事。”我说的不是这种 HTML5，不是这种涵盖了最近刚刚出现的各种新东东的 HTML5。我说的仅仅是规范本身：HTML5。</p><p>刚才已经说了，我今天想要讲的内容不多，也没有打算介绍 HTML5 都包含什么。今天我要讲的是它的另一方面，即 HTML5 的设计。换句话说，我要讲的不是规范里都包含什么，而是规范里为什么会包含它们，以及在设计这个规范的时候，设计者们是怎么看待这些东西的。</p><h2 id="设计原理"><a href="#设计原理" class="headerlink" title="设计原理"></a>设计原理</h2><p>设计原理本质上是一种信念、一种想法、一个概念，是你行动的支柱。不管你是制定规范，还是制造一种有形的物品，或者编写软件，甚至发明编程语言。你都能找到背后的一个或者多个设计原理，多人协作的任何成果都是例证。不仅仅 Web 开发领域是这样。纵观人类历史，像国家和社会这样大规模的构建活动背后，同样也有设计原理。</p><p>就拿美国为例吧，美国的设计原理都写在了《独立宣言》中了。</p><blockquote><p>我们认为这些真理是不言而喻的，人人生而平等，造物主赋予了每个人不可剥夺的权利，包括生存、自由和追求幸福。</p></blockquote><p>这里有一句口号：生存、自由和追求幸福。这是被写进宪法中的核心理念，它关系到我们所有人的一切，也就是我们构建自己社会的原则。</p><p>还有一个例子，就是卡尔·马克思（Karl Marx），他的著作在 20 世纪曾被奉为建设社会主义的圭臬。其基本思想大致可以归结为下面这条设计原理：</p><blockquote><p>各尽所能，各取所需。</p></blockquote><p>这其实就是一种经济体系背后的设计原理。</p><p>还有一个例子，比前面两个的历史更久远一些，不过大同小异：</p><blockquote><p>人人为我，我为人人。</p></blockquote><p>这个极为简单的设计原理，是两千年前的拿撒勒犹太人耶稣基督提出来的。而这条原则成为了后来许多宗教的核心教义。原理与实践有时候并不是同步的。</p><p>下面是小说中的一个例子。英国小说家乔治·奥威尔（George Orwell）笔下的《动物庄园》，就是在一条设计原理的基础上构建起来的虚拟社会。这条设计原理是：</p><blockquote><p>四条腿的都是好人，两条腿的都是坏蛋！</p></blockquote><p>《动物庄园》中有意思的是，随着社会的变迁——变得越来越坏，这条设计原理也跟着发生了改变，变成了“四条腿的都是好人，两条腿的就更好了。”最关键的是，即使是在虚构的作品里，设计原理都是存在的。</p><p>还有一套虚构的作品是以三条设计原理为基础构建起来的，那就是美国著名小说家艾萨克·阿西莫夫（Issac Asimov）的机器人经典系列。阿西莫夫发明了机器人学这个术语，并提出了机器人学三大法则，然后在这三个简单的设计原理基础上创作了一系列经典作品——大约有 50 本书。无论作品的情节如何变化，实际上都是从不同的角度来阐释这三大设计原理。我想，在座各位对机器人三大法则都不应该陌生。</p><blockquote><p>机器人不得伤害人类，或袖手旁观人类受伤害。<br>机器人必须服从人类命令，除非命令违反第一法则。<br>机器人必须自卫，只要不违背第一和第二法则。</p></blockquote><p>这些恐怕是第一次出现在小说中的针对软件的设计原理了。虽然基于这三个设计原理的软件运行在虚构的机器人的“正电子脑”中，但我想这应该是软件设计原理的事实开端。从此以后，我们才看到大量优秀软件背后的设计原理。</p><p>蒂姆·伯纳斯 - 李（Tim Berners-Lee），Web 的发明者，在 W3C 的网站上发表过一份文档，其中有一个 URL 给出了他自己的一套设计原理。这些设计原理并不那么容易理解，不仅多，而且随着时时间推移，他还会不断补充、修改和删除。不过我还是觉得把自己认同的设计原理写出来放在某个地方真是个不错的主意。</p><p>实际上，CSS 的发明人之一伯特·波斯（Bert Bos），也在 W3C 的网站上放着一份文档，其中讲的都是基本的设计原理，比如怎样设计并构建一种格式，无论是 CSS 还是其他格式。推荐大家看一看。</p><p>只要你在 W3C 的站点中随便找一找，就可以发现非常多的这种设计原理，包括蒂姆·伯纳斯 - 李个人的。当然，你还会看到他从软件工程学校里借用的一些口号：分权（decentalisation）、容忍（tolerance）、简易（simplicity）、模块化（modularity）。这些都是在他发明新格式的时候，头脑中无时无刻不在想的那些关键词。</p><p>在座各位对蒂姆·伯纳斯 - 李的贡献都是非常熟悉的，因为大家每天都在用。他发明了 Web，与罗伯特·卡里奥（Robert Cailliau）共同发明了 Web，而且在发明 Web 的同时，也发明了我们每天都在 Web 上使用的语言。当然，这门语言就是 HTML：超文本标记语言。</p><h2 id="HTML"><a href="#HTML" class="headerlink" title="HTML"></a>HTML</h2><p>HTML 最早是从 2.0 版开始的。从来就没有 1.0 版。如果有人告诉你说，他最早是从 HTML 1.0 开始使用 HTML 的，那他绝对是在忽悠你。从前确实有一个名叫 HTML Tags 的文档，其中的部分标签一直用到现在，但那个文档并非官方的规范。</p><p>使用标签、尖括号、p 或 h1，等等，并不是蒂姆·伯纳斯 - 李首创的想法。当时的 SGML 里就有了这些概念，而且当时的 CERN（Conseil Europeen pour la Recherche Nucleaire，欧洲核子研究委员会）也在使用 SGML 的一个特定的版本。也就是说，即便在那个时代，他也没有白手起家；这一点在 HTML 后来的发展过程中也体现了出来：继往开来、承前启后，而不是另立门户、从头开始。</p><p>换句话说，这篇名为 HTML Tags 的文档可以算作 HTML 的第一个版本，但它却不是一个正式的版本。第一个正式版本，HTML 2.0，也不是出自 W3C 之手。HTML 2.0 是由 IETF，因特网工程任务组（Internet Engineering Task Force）制定的。在 W3C 成立之前，IETF 已经发布了不少标准。但从第三个版本开始往后，W3C，万维网联盟（World Wide Web Consortium）开始接手，并负责后续版本的制定工作。</p><p>20 世纪九十年代 HTML 有过几次快速的发展。众所周知，在那个时代要想构建网站，可是一项十分复杂的工程。浏览器大战曾令人头疼不已。市场竞争的结果就是各家浏览器里都塞满了各种专有的特性，都试图在专有特性上胜人一筹。当时的混乱程度不堪回首，HTML 到底还重不重要，或者它作为 Web 格式的前景如何，谁都说不清楚。</p><p>从 1997 年到 1999 年，HTML 的版本从 3.2 到 4.0 到 4.01，经历了非常快的发展。问题是到了 4.01 的时候，W3C 的认识发生了倒退，他们说“好了，这个版本就这样了，HTML 也就这样了；HTML 4.01 是 HTML 的最后一个版本了，我们用不着 HTML 工作组了。”</p><p>W3C 并没有停止开发这门语言，只不过他们对 HTML 不再感兴趣了。在 HTML 4.01 之后，他们提出了 XHTML 1.0。虽然听起来完全不同，但 XHTML 1.0 与 HTML 4.01 其实是一样的。我的意思是说，从字面上看这两个规范的内容是一样的，词汇表是一样的，所有的元素是一样，所有的属性也都是一样的。唯一一点不同之处，就是 XHTML 1.0 要求使用 XML 语法。也就是说，所有属性都必须使用小写字母，所有元素也必须使用小写字母，所有属性值都必须加引号，你还得记着使用结束标签，记着对 img 和 br 要使用自结束标签。</p><p>从规范本身的内容来看，实际上是相同的，没有什么不同。不同之处就是编码风格，因为对浏览器来说，读取符合 HTML 4.01、HTML 3.2，或者 XHTML 1.0 规范的网页都没有问题，对浏览器来说这些网页都是一样的，都会生成相同的 DOM 树。只不过人们会比较喜欢 XHTML 1.0，因为不少人认同它比较严格的编码风格。</p><p>到了 2000 年，Web 标准项目（Web Standards Project）的活动开展得如火如荼，开发人员对浏览器里包含的那些乱七八糟的专有特性已经忍无可忍了。大家都很生气，就骂那些浏览器厂商“遵守个规范就他妈的真有那么难吗？”当时 CSS 有了长足的发展，而且与 XHTML 1.0 结合得也很紧密，CSS 加 XHTML 1.0 基本上就可以算是“最佳实践”了。虽然在我看来 HTML 4.01 与 XHTML 1.0 没有本质上的不同，但大家都接受了。专业的开发人员能做到元素全部小写，属性全部小写，属性值也全部加引号：由于专业人员起到了模范带头作用，越来越多的人也都开始支持这种语法。</p><p>我就是一个例子！过去的 10 年，我一直都使用 XHTML 1.0 文档类型，原因是这样一来验证器就能给我帮上很大的忙，对不对？只要我写的是 XHTML 1.0，然后用验证器测试，它就能告诉我是不是忘了给属性值加引号，是不是没有结束某个标签，等等等等。而如果我写的是 HTML 4.01，同样的问题就变成了有效的了，验证器就不一定会提醒我了。</p><p>这就是我一直使用 XHTML 1.0 的原因。我估计很多人都……使用 XHTML 1.0 的朋友，请把手举起来。好的。HTML 4.01 呢？人少多了。一直没有举手的呢，大声点，你们用什么？HTML5，也很好！更早的呢，还有人使用更早的文档类型吗？没有了？</p><p>10 年来我一直使用 XHTML 1.0，就是因为验证器能够真正帮到我。有人用 XHTML 1.1 吗？你知道有人用吗？请举手，别放下。有人把网页标记为 XML 文档吗？有吗？那你们使用的就不是 XHTML 1.1。</p><p>这就是个大问题。XHTML 1.0 之后是 XHTML 1.1，只是小数点后面的数字加了一个 1，而且从词汇表的角度看，规范本身没有什么新东西，元素也都相同，属性也都相同。但对 XHTML 1.1 来说，唯一的变化是你必须把自己的文档标记为 XML 文档。在使用 XHTML 1.0 的时候，还可以把文档标记为 HTML，而我们也正是这样做的，否则把文档标记为 XML 没准真会把人逼疯的。</p><p>为什么这么说呢？首先，把文档标记为 XML 后，Internet Explorer 不能处理。当然，IE9 是可以处理了。恐怕有人会讲“真是太可爱了”，他们到现在居然都没有忘了这件事。这艘船终于靠岸了！不过那时候，作为全球领先的浏览器，IE 无法处理接收到的 XML 文档类型的文档，而规范又要求你以 XML 文档类型来发送文档，这不把人逼疯才怪呢。</p><p>所以说 XHTML 1.1 有点脱离现实，而你不想把文档以 XML 格式发送给那些能够理解 XML 的浏览器，则是因为 XML 的错误处理模型。XML 的语法，无论是属性小写，元素小写，还是始终要给属性值加引号，这些都没有问题，都很好，事实上我也喜欢这样做，但 XML 的错误处理模型却是这样的：解析器如果遇到错误，停止解析。规范里就是这么写的。如果你把 XHTML 1.1 标记为 XML 文档类型，假设你用 Firefox 打开这个文档，而文档中有一个和号（&amp;）没有正确编码，就算整个页面中就这一处错误，你看到的也将是黄屏，浏览器死掉了。Firefox 会说：“没戏了，页面中有一个错误，你看不到这个网页了。”根据 XML 规范，这样处理是正确的，对 Firefox 而言，遇到错误就停止解析，并且不呈现其他任何内容是严格按照 XML 规范做的。因为它不是 HTML，HTML 根本就没有错误处理模型，但根据 XML 规范，这样做没错。</p><p>这就是为什么你不会把文档标记为 XML 的另一个原因。接下来，新的版本是 XHTML 2，大家注意后面没有日期，因为这个规范并没有完成。</p><p>现在就说说 XHTML 2，我很愿意把问题说清楚，XHTML 2 实际上真是一个非常非常好的规范，确实非常好……从理论的角度来说。我的意思是说，制定这个规范的人都是非常非常有头脑的。直说吧，领导制定这个规范的家伙是斯蒂芬·彭伯顿（Stephen Pemberton），他应该是本地人，是一个聪明过人的家伙。规范本身也很了不起，如果所有人都同意使用的话，也一定是一个非常好的格式。只不过，还不够实际。</p><p>首先，XHTML 2 仍然使用 XML 错误处理模型，你必须保证以 XML 文档类型发送文档；这一点不言自明：没人愿意这样做。其次，XHTML 2 有意不再向后兼容已有的 HTML 的各个版本。他们甚至曾经讨论过废除 img 元素，这对每天都在做 Web 开发的人来说确实有点疯了的味道。但我们知道，他们之所以这样做，理论上确实有充足的理由——使用 object 元素可能会更好。</p><p>因此，无论 XHTML 2 在理论上是多么完美的一种格式，但却从未有机会付诸实践。而之所以难以将其付诸实践，就是因为像你我这样的开发人员永远不会支持它，它不向后兼容。同样，浏览器厂商也不会，浏览器厂商必须要保证向后兼容。</p><p>为什么 XHTML 1.1 没有像 XML 那样得到真正广泛地应用，为什么 XHTML 2 从未落到实处？因为它违反了一条设计原理，这条设计原理就是著名的伯斯塔尔法则（Postel’s Law）。大家都知道：</p><blockquote><p>发送时要保守；接收时要开放。</p></blockquote><p>没错，接收的时候要开放，而这也正是 Web 得以构建的基础。开发浏览器的人必须敞开胸怀，接收所有发送给浏览器的东西，因为它们过去一直都在接收那些不够标准的东西，对不对？Web 上的很多文档都不规范，但那正是 Web 发展的动力。从某种角度讲，Web 走的正是一条混沌发展之路，虽然混沌，但却非常美丽诱人。在 Web 上，格式不规范的文档随处可见，但那又怎样呢？如果所有人都能够写出精准的 XML，所有文档的格式都十分正确，那当然好了。可是，那不现实。现实是伯斯塔尔法则。</p><p>作为专业人士，在发送文档的时候，我们会尽量保守一些，尽量采用最佳实践，尽量确保文档格式良好。但从浏览器的角度说，它们必须以开放的姿态去接收任何文档。</p><p>有人可能会说 XML 有错误处理模型，XHTML 1.1 和 XHTML 2 都使用该模型，但那个错误处理模型太苛刻了。它绝对不符合接收时开放这个法则，遇到一个错误就停止解析怎么能叫开放呢？我们只能说它与健壮性法则（也就是伯斯塔尔法则）是对立的。</p><h2 id="HTML5"><a href="#HTML5" class="headerlink" title="HTML5"></a>HTML5</h2><p>之后，就到了 HTML5，但 HTML5 并不是由 W3C 直接制定的。故事的经过是这样的，到 20 世纪末的时候，还没有 HTML 工作组，W3C 内部的一些人就开始琢磨了，“HTML 也许还可以更长寿一点，只要我们对它稍加扩展就行了。只要把我们放在 XHTML 上的时间和精力拿出一部分来，就可以提升一下 HTML 中的表单，可以让 HTML 更接近编程语言，就可以让它更上一层楼。”</p><p>于是，在 2004 年 W3C 成员内部的一次研讨会上，当时 Opera 公司的代表伊恩·希克森（Ian Hickson）提出了一个扩展和改进 HTML 的建议。他建议新任务组可以跟 XHTML 2 并行，但是在已有 HTML 的基础上开展工作，目标是对 HTML 进行扩展。W3C 投票表决的结果是——“反对”，因为 HTML 已经死了，XHTML 2 才是未来的方向。然后，Opera、Apple 等浏览器厂商，以及其他一些成员说：“那好吧，不指望他们了，我们自已一样可以做这件事，我们脱离 W3C。”他们成立了 Web Hypertext Applications Technology Working Group（Web 超文本应用技术工作组，WHATWG）——可巧的是，他们自称工作组，而不是特别小组（task force），这就为 HTML5 将来的命运埋下了伏笔。</p><p>WHATWG 决定完全脱离 W3C，在 HTML 的基础上开展工作，向其中添加一些新东西。这个工作组的成员里有浏览器厂商，因此他们不仅可以说加就加，而且还能够一一实现。结果，大家不断提出一些好点子，并且逐一做到了浏览器中。</p><p>WHATWG 的工作效率很高，不久就初见成效。在此期间，W3C 的 XHTML 2 没有什么实质性的进展。特别是，如果从实现的角度来说，用原地踏步形容似乎也不为过。</p><p>结果，一件有意思的事情发生了。那是在 2006 年，蒂姆·伯纳斯 - 李写了一篇博客，说：“你们知道吗？我们错了。我们错在企图一夜之间就让 Web 跨入 XML 时代，我们的想法太不切实际了，是的，也许我们应该重新组建 HTML 工作组了。”善哉斯言，后来的故事情节果真就是这样发展的。W3C 在 2007 年组建了 HTML5 工作组。这个工作组面临的第一个问题，毫无疑问就是“我们是从头开始做起呢，还是在 2004 年成立的那个叫 WHATWG 的工作组既有成果的基础上开始工作呢？”答案是显而易见的，他们当然希望从已经取得的成果着手，以之为基础展开工作。于是他们又投了一次票，同意“在 WHATWG 工作成果的基础上继续开展工作”。好了，这下他们要跟 WHATWG 并肩战斗了。</p><p>第二个问题就是如何理顺两个工作组之间的关系。W3C 这个工作组的编辑应该由谁担任？是不是还让 WHATWG 的编辑，也就是现在 Google 的伊恩·希克森来兼任？于是他们又投了一次票，赞成“让伊恩·希克森担任 W3C HTML5 规范的编辑，同时兼任 WHATWG 的编辑，更有助于新工作组开展工作。”</p><p>这就是他们投票的结果，也就是我们今天看到的局面：一种格式，两个版本。WHATWG 的网站上有这个规范，而 W3C 的站点上同样也有一份。</p><p>如果你不了解内情，很可能会产生这样的疑问：“哪个版本才是真正的规范？”当然，这两个版本内容是一样的……基本上相同。实际上，这两个版本将来还会分道扬镳。现在已经有了分道扬镳的迹象了。我的意思是说，W3C 最终要制定一个具体的规范，这个规范会成为一个工作草案，定格在某个历史时刻。</p><p>而 WHATWG 呢，他们还在不断地迭代。即使目前我们说的 HTML5，也不能完全涵盖 WHATWG 正在从事的工作。最准确的理解是他们正在开发一项简单的 HTML 或 Web 技术，因为这才是他们工作的核心目标。然而，同时存在两个这样的工作组，这两个工作组同时开发一个基本相同的规范，这无论如何也容易让人产生误解。误解就可能造成麻烦。</p><p>其实这两个工作组背后各自有各自的流程，因为它们的理念完全不同。在 WHATWG，可以说是一种独裁的工作机制。我刚才说了，伊恩·希克森是编辑。他会听取各方意见，在所有成员各抒己见，充分陈述自己的观点之后，他批准自己认为正确的意见。<br>W3C 则截然相反，可以说是一种民主的工作机制。所有成员都可以发表意见，而且每个人都有投票表决的权利。这个流程的关键在于投票表决。从表面上看，WHATWG 的工作机制让人不好接受。岂止是不好接受，简直是历史的倒退。相信谁都会认为“运作任何项目都不能采取这种方式！”</p><p>W3C 的工作机制听起来让人很舒服。至少体现了人人平等嘛。但在实践中，WHATWG 的工作机制运行得非常非常好。我认为之所以会这样，主要归功于伊恩·希克森。他的的确确是一个非常称职的编辑。他在听取各方意见时，始终可以做到丝毫不带个人感情色彩。</p><p>从原理上讲，W3C 的工作机制很公平，而实际上却非常容易在某些流程或环节上卡壳，造成工作停滞不前，一件事情要达成决议往往需要花费很长时间。那到底哪种工作机制最好呢？我认为，最好的工作机制是将二者结合起来。而事实也是两个规范制定主体在共同制定一份相同的规范，我想，这倒是非常有利于两种工作机制相互取长补短。</p><p>两个工作组之所以能够同心同德，主要原因是 HTML5 的设计思想。因为他们从一开始就确定了设计 HTML5 所要坚持的原则。结果，我们不仅看到了一份规范，也就是 W3C 站点上公布的那份文档，即 HTML5 语言规范，还在 W3C 站点上看到了另一份文档，也就是 HTML 设计原理。而这份文档的一位编辑今天也来到了我们大会的现场，他就是安妮·奇泰丝（Anne Van Kesteren）。如果大家对这份文档有问题，可以请教安妮。</p><p>这份文档非常好，真的非常出色。这份文档，可以说见证了 W3C 与 WHATWG 同心协力共谋发展的历程。难道你们不觉得他们像是一对欢喜冤家吗？那他们还怎么同心同德呢？这份文档忠实地记录了他们一道做了什么，他们共同拥护什么。</p><p>接下来，我想要讲的就是这份文档。因为，既然他们能就这份文档达成共识，那么我相信，HTML5 必将是一个伟大的规范，而他们已经认可这就是他们的共同行动纲领。为此，你才会看到诸如兼容性、实用性、互用性之类的概念。即便 W3C 与 WHATWG 之间再有多大的分歧——确实相当多——至少他们还有这份文档中记录的共识。这一点才是至关重要的。正因为他们有了共识，才有了这份基于共识描述设计原理的文档。</p><h2 id="避免不必要的复杂性"><a href="#避免不必要的复杂性" class="headerlink" title="避免不必要的复杂性"></a>避免不必要的复杂性</h2><p>下面我就给大家介绍一些这份文档中记载的设计原理。第一个，非常简单：避免不必要的复杂性。好像很简单吧。我用一个例子来说明。</p><p>假设我使用 HTML 4.01 规范，我打开文档，输入 doctype。这里有人记得 HTML 4.01 的 doctype 吗？好，没有，我猜没有。除非……我的意思是说，你是傻冒。现场恐怕真有人背过，这就是 HTML 4.01 的 doctype：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">html</span> <span class="keyword">PUBLIC</span> <span class="string">&quot;-//W3C/DTD HTML 4.01//EN&quot;</span> <span class="string">&quot;http://www.w3.org/TR/html4/strict.dtd&quot;</span>&gt;</span></span><br></pre></td></tr></table></figure><p>我不记这个两行代码，不然还要记事本、要 Google、要模板有什么用呢？</p><p>要是我使用 XHTML 1.0 呢，这个规范我都已经用了 10 年了。有谁记得住这个 doctype 吗？没错，它的长度跟 HTML 4.01 的差不太多：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">html</span> <span class="keyword">PUBLIC</span> <span class="string">&quot;-//W3C/DTD XHTML 1.0 Strict//EN&quot;</span> <span class="string">&quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd&quot;</span>&gt;</span></span><br></pre></td></tr></table></figure><p>是不是，基本上相同。它要告诉浏览器的是：这个文档是 XHTML 1.0 的文档。那么在 HTML 5 中，省掉不必要的复杂性，doctype 就简化成了：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">html</span>&gt;</span></span><br></pre></td></tr></table></figure><p>仅此而已。好了，就连我也能过目不忘了。我用不着把这几个字符记在记事本里了。我得说，在我第一次看到这个 doctype 的时候——我当然以为这是一个 HTML 文档的 doctype——被它吓了一跳：“是不是还少一个数字 5 啊？”我心里想：“这个 doctype 想告诉浏览器什么呢？就说这个文档是 HTML 吗？难道这是有史以来唯一一个 HTML 版本吗，这件事我得首先搞清楚，HTML 今后永远不会再有新版本了吗？”好一副唯我独尊的架式！我错了，因为这个 doctype 并没有这个意思。为此，必须先搞清楚为什么文档一开头就要写 doctype。它不是写给浏览器看的。Doctype 是写给验证器看的。也就是说，我之所以要在文档一开头写那行 XHTML 1.0 的 doctype，是为了告诉验证器，让验证器按照该 doctype 来验证我的文档。</p><p>浏览器反倒无所谓了。假设我写的是 HTML 3.2 文档，文档开头写的是 HTML 3.2 的 doctype。而在文档中某个地方，我使用了 HTML 4.01 中才出现的一个元素。浏览器会怎么处理这种情况？它会因为这个元素出现在比 doctype 声明的 HTML 版本更晚的规范中，就不解释呈现该元素吗？不会，当然不会！它照样会解释呈现该元素，别忘了伯斯塔尔法则，别忘了健壮性。浏览器在接收的时候必须要开放。因此，它不会检查任何格式类型，而验证器会，验证器才关心格式类型。这才是存在 doctype 的真正原因。</p><p>而按照 HTML5 的另一个设计原理，它必须向前向后兼容，兼容未来的 HTML 版本——不管是 HTML6、HTML7，还是其他什么——都要与当前的 HTML 版本，HTML5，兼容。因此，把一个版本号放在 doctype 里面没有多大的意义，即使对验器证也一样。</p><p>刚才，我说 doctype 不是为浏览器写的，这样说大多数情况下没有问题。在有一种情况下，你使用的 doctype 会影响到浏览器，相信在座诸位也都知道。但在这种情况下，Doctype 并非真正用得其所，而只是为了达到某种特殊的目的才使用 doctype。当初微软在引入 CSS 的时候，走在了标准的前头，他们率先在浏览器中支持 CSS，也推出了自己的盒模型——后来标准发布了，但标准中使用了不一样的盒模型。他们怎么办？他们想支持标准，但也想向后兼容自己过去推出的编码方式。他们怎么知道网页作者想使用标准，还是想使用他们过去的方式？</p><p>于是，他们想出了一个非常巧妙的主意。那就是利用 doctype，利用有效的 doctype 来触发标准模式，而不是兼容模型（quiks mode）。这个主意非常巧妙。我们今天也都是这样在做，在我们向文档中加入 doctype 时，就相当于声明了“我想使用标准模式”，但这并不是发明 doctype 的本意。这只是为了达到特殊的目的在利用 doctype。</p><p>下面我出一道有奖抢答题，听好：“一分钟后开始，如果你手快的话，第一个在文档前面写完 doctype html，然后我用 Internet Explorer 打开你的文档，会触发它的标准模式，还是会触发它的兼容模式？”</p><p>答案是，这是在 Internet Explorer 中触发标准模式的最少字符数目。我认为这也说明了 HTML5 规范的本质：它不追求理论上的完美。HTML5 所体现的不是“噢，给作者一个简短好记的 doctype 不好吗？”，没错，简短好记是很好，但如果这个好记的 doctype 无法适应现有的浏览器，还不如把它忘了更好。因此，这个平衡把握得非常好，不仅理论上看是个好主意——简短好记的 doctype，而且实践中同样也是个好主意——仍然可以触发标准模式。应该说，Doctype 是一个非常典型的例子。</p><p>还有一个例子，同样可以说明规范是如何省略不必要的复杂性，避免不必要的复杂性的。如果前面的文档使用的是 HTML 4.01，假设我要指定文档的字符编码。理想的方式，是通过服务器在头部信息中发送字符编码，不过也可以在文档这个级别上指定：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">&quot;Content-Type&quot;</span> <span class="attr">content</span>=<span class="string">&quot;text/html; charset=utf-8&quot;</span>&gt;</span></span><br></pre></td></tr></table></figure><p>同样，我也不会把这行代码背下来。我还想省下自己的脑细胞去记点别的更有价值的东西呢。不过，如果我想指定文档使用 UTF-8 编码，只能添加这行代码。这是在 HTML 4.01 中需要这样做。要是你在 XHTML 1.0 指定同样的编码，就得多敲一下键盘，因为你还得声明 meta 元素位于一个开始的 XML 标签中。</p><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span> ?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">&quot;Content-Type&quot;</span> <span class="attr">content</span>=<span class="string">&quot;text/html; charset=utf-8&quot;</span> /&gt;</span></span><br></pre></td></tr></table></figure><p>在 HTML5 中，你要敲的字符只有：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;utf-8&quot;</span>&gt;</span></span><br></pre></td></tr></table></figure><p>简短好记。我能背下来。</p><p>同样，这样写也是有效的。它不仅适用于最新版本的浏览器，只要是今天还有人在用的浏览器都同样有效。为什么？因为在我们把这些 meta 元素输入浏览器时，浏览器会这样解释它：“元数据（meta）点点点点点，字符集（charset）utf-8。”这就是浏览器在解释那行字符串时真正看到的内容。它必须看到这些内容，根据就是伯斯塔尔法则，对不对？</p><p>我多次提到健壮性原理，但总有人不理解。我们换一种说法，浏览器会想“好，我觉得作者是想要指定一个字符集……看，没错，utf-8。”这些都是规范里明文规定的。如今，不仅那个斜杠可以省了，而且总共只要写 meta charset&#x3D;”utf-8″就行了。</p><p>关于省略不必要的复杂性，或者说避免不必要的复杂性的例子还有不少。但关键是既能避免不必要的复杂性，还不会妨碍在现有浏览器中使用。比如说，在 HTML5 中，如果我使用 link 元素链接到一个样式表，我说了 rel&#x3D;”stylesheet”，然后再说 type&#x3D;”text&#x2F;css”，那就是重复自己了。对浏览器而言，我就是在重复自己。浏览器用不着同时看到这两个属性。浏览器只要看到 rel&#x3D;”stylesheet”就够了，因为它可以猜出来你要链接的是一个 CSS 样式表。所以就不用再指定 type 属性了。你不是已经说了这是一个样式表了嘛；不用再说第二次了。当然，愿意的话，你可以再说；如果你想包含 type 属性，请便。</p><p>同样地，如果你使用了 script 元素，你说 type&#x3D;”text&#x2F;javascript”，浏览器差不多就知道是怎么回事了。对 Web 开发而言，你还使用其他的脚本语言吗？如果你真想用其他脚本语言，没人会阻拦你。但我要奉劝你一句，任何浏览器都不会支持你。<br>愿意的话，你可以添加一个 type 属性。不过，也可以什么都不写，浏览器自然会假设你在使用 JavaScript。避免 - 不必要的 - 复杂性。</p><h2 id="支持已有的内容"><a href="#支持已有的内容" class="headerlink" title="支持已有的内容"></a>支持已有的内容</h2><p>支持已有的内容。这一点非常重要，因为很多人都认为 HTML5 很新，很闪亮；它应该代表着未来发展的方向，应该把 Web 推向一个新的发展阶段。这就是 HTML5，对吗？显然，我们都会考虑让 Web 的未来发展得更好，但他们则必须考虑过去。别忘了 W3C 这个工作组中有很多人代表的是浏览器厂商，他们肯定是要考虑支持已有内容的。只要你想构建一款浏览器，就必须记住这个原则：必须支持已有的内容。</p><p>下面我们就来看一个 HTML5 支持已有内容的例子。</p><p>这个例子展示了编写同样内容的四种不同方式。上面是一个 img 元素，下面是带一个属性的段落元素。四种写法唯一的不同点就是语法。把其中任何一段代码交给浏览器，浏览器都会生成相同的 DOM 树，没有任何问题。从浏览器的角度看，这四种写法没有区别。因而在 HTML5 中，你可以随意使用下列任何语法。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">&quot;foo&quot;</span> <span class="attr">alt</span>=<span class="string">&quot;bar&quot;</span> /&gt;</span> <span class="tag">&lt;<span class="name">p</span> <span class="attr">class</span>=<span class="string">&quot;foo&quot;</span>&gt;</span>Hello world<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">&quot;foo&quot;</span> <span class="attr">alt</span>=<span class="string">&quot;bar&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">p</span> <span class="attr">class</span>=<span class="string">&quot;foo&quot;</span>&gt;</span>Hello world</span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">IMG</span> <span class="attr">SRC</span>=<span class="string">&quot;foo&quot;</span> <span class="attr">ALT</span>=<span class="string">&quot;bar&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">P</span> <span class="attr">CLASS</span>=<span class="string">&quot;foo&quot;</span>&gt;</span>Hello world<span class="tag">&lt;/<span class="name">P</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">foo</span> <span class="attr">alt</span>=<span class="string">bar</span>&gt;</span><span class="tag">&lt;<span class="name">p</span> <span class="attr">class</span>=<span class="string">foo</span>&gt;</span>Hello world<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br></pre></td></tr></table></figure><p>好了，看到这几段代码，恐怕有人会说“不对不对不对。其中只有一个是对的，另外三个——说不好。”不对，应该给属性值加引号！拜托，我们可是一直都给属性值加引号的！元素名大写对吗？这种做法 10 年不是就被抛弃了吗？</p><p>看到 HTML5 同时允许这些写法，我心里忍不住一阵阵想吐。我写了 10 年的 XHTML 1.0，已经非常适应严格的语法了。但你必须明白，站在浏览器的角度上，这些写法实际上都是一样的。确实没有什么问题。</p><p>还有谁也感到不舒服了吗？有谁看到这些之后想“噢，这不是乱写嘛，这样做不对”？只有我这样想吗？还有别人吗？</p><p>但是，HTML5 必须支持已经存在的内容，而已有的内容就是这个样子的。不是吗？根据伯斯塔尔法则，浏览器没有别的选择。</p><p>有人可能会说“这样不行。我觉得语言本身应该提供一种开关，让作者能够表明自己想做什么。”比如说，想使用某种特定的语法，像 XHTML，而不是使用其他语法。我理解这些人的想法。但我不赞成在语言里设置开关。因为我们讨论的只是编码风格或者写作风格，跟哪种语法正确无关。对于像我们这样的专业人士，我认为可以使用 lint 工具（一种软件质量保证工具，或者说是一种更加严格的编译器。它不仅可以象普通编译器那样检查出一般的语法错误，还可以检查出那些虽然完全合乎语法要求，但很可能是潜在的、不易发现的错误），对其他技术我们不是也在使用 lint 工具嘛。</p><p>比如说对 JavaScript 使用 lint 工具。JavaScript 同样也是比较混乱、不严谨的例子，但它非常强大，原因恰恰是它混乱、不严谨，而且有很多不同的编码方式。在 JavaScript，你可以在每条语句末尾加上分号，但不是必需的，因为 JavaScript 会自动插入分号……是不是听起来有点不好接受？</p><p>正因为如此，才有了像 JSlint 这样的工具，在道格拉斯·克劳克福德（Douglas Crockford）的网站 jslint.org 上面。有个网页上写着“JSlint 可能会伤害你的感情。”但这确实是个非常棒的工具，它可以把 JavaScript 代码变得完美无瑕。如果你通过 JSlint 运行 JavaScript，它会告诉你“好，你的 JavaScript 代码有效，但写法不妥。你这种编码风格啊，我不喜欢。不赞成你这样写。这样写不好。”特别是对团队，对于要使用统一的编码风格的团队，JSlint 是非常方便的工具。</p><p>我个人认为，不仅对团队来说，就算是你自己写代码，也要坚持一种语法风格。从浏览器解析的角度讲，不存在哪种语法比另一种更好的问题，但我认为，作为专业人士，我们必须能够自信地讲“这就是我的编码风格。”然而，我不认为语言里应该内置这种开关。你可以使用 lint 工具来统一编码风格。现在就来说说 lint 工具。大家可以登录 htmllint.com，在其中运行你的 HTML5 文档，它会帮你检查属性值是否加了引号，元素是否小写，你还可以通过勾选复选框来设置其他检查项。</p><p>但这不意味着拒绝粗心大意的标记，做不做清理完全取决于你自己。我说过，因为浏览器必须支持已有的内容，HTML5 自然也不能例外。归根结底还是伯斯塔尔法则。我们始终离不开伯斯塔尔法则。</p><p>解决现实的问题<br>HTML5 的另一个设计原理是解决现实的问题。显而易见的是，解决各种问题的格式和规范已经比比皆是了，但是在我看来，那些格式和规范要解决的都是理论问题，而非现实问题。这条设计原理才是真正要解决今天的人们所面临的现实问题、令人头疼的问题。</p><p>下面我来举个例子。相信这个例子有不少人都遇到过。假设我使用 HTML 4 或 XHTML 1，页面中已经有了一块内容，我想给整块内容加个链接，怎么办？问题是这块内容里包含一个标题，一个段落，也许还有一张图片。如果我想给它们全部都可以点击，必须使用 3 个链接元素。于是，我得先把光标放在标题（比如说 h2 元素）中，写一个链接标签，然后再选中所有要包含到链接里面来的文本。接着，再把光标放在段落里，写一个链接标签，然后把段落中的文本放在链接里……</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">h2</span>&gt;</span><span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">&quot;/path/to/resource&quot;</span>&gt;</span>Headline text<span class="tag">&lt;/<span class="name">a</span>&gt;</span><span class="tag">&lt;/<span class="name">h2</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">p</span>&gt;</span><span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">&quot;/path/to/resource&quot;</span>&gt;</span>Paragraph text.<span class="tag">&lt;/<span class="name">a</span>&gt;</span><span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br></pre></td></tr></table></figure><p>在 HTML5 中，我只要简单地把所有内容都包装在一个链接元素中就行了。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">&quot;/path/to/resource&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">h2</span>&gt;</span>Headline text<span class="tag">&lt;/<span class="name">h2</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">p</span>&gt;</span>Paragraph text.<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br></pre></td></tr></table></figure><p>没错，链接包含的都是块级元素，但现在我可以用一个元素包含它们。这样太好了。因为我碰到过类似的情形，必须给几个块级元素加上相同的链接，所有能这样写就太好了。为此，我就非常欢迎 HTML5 这个新标准。</p><p>它解决了一个现实的问题。我敢说在座不少朋友都曾遇到过这个问题。</p><p>那这到底解决的是什么问题呢？浏览器不必因此重新写代码来支持这种写法。这种写法其实早就已经存在于浏览器中了，因为早就有人这样写了，当然以前这样写是不合乎规范的。所以，说 HTML5 解决现实的问题，其本质还是“你都这样写了很多年了吧？现在我们把标准改了，允许你这样写了。”</p><h2 id="求真务实"><a href="#求真务实" class="headerlink" title="求真务实"></a>求真务实</h2><p>在所有设计原理中，这一条恐怕是最响亮的了——求真务实。不知道大家有没有在公司里开会时听到过这种口号：“开拓进取，求真务实。”实际上，除了作为企业的口号，它还是一条非常重要的设计原理，因为求真务实对于 HTML 的含义是：在解决那些令人头痛的问题之前，先看看人们为应对这些问题都想出了哪些办法。集中精力去理解这些“民间的”解决方案才是当务之急。</p><p>HTML5 中新的语义元素就是遵循求真务实原理的反映。新增的元素不算多，谈不上无限的扩展性，但却不失为一件好事。尽管数量屈指可数，但意义却非同一般。这些新元素涉及头部（header）、脚部（footer）、分区（section）、文章（article）……，相信大家都不会觉得陌生。我的意思是说，即便你不使用 HTML5，也应该熟悉这些称呼，这些都是你曾经使用过的类名，比如 class&#x3D;”header”&#x2F;“head”&#x2F;“heading”，或 class&#x3D;”footer”&#x2F;“foot”。当然，也可能是 ID，id&#x3D;”header”，id&#x3D;”footer”。这些不都是我们已经司空见惯了的嘛。</p><p>好，举个例子吧，假设你今天写了下面这个文档。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;header&quot;</span>&gt;</span>...<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;navigation&quot;</span>&gt;</span>...<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;main&quot;</span>&gt;</span>...<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;sidebar&quot;</span>&gt;</span>...<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;footer&quot;</span>&gt;</span>...<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br></pre></td></tr></table></figure><p>这里有一个 div 使用了 id&#x3D;”header”，另一个 div 使用了 id&#x3D;”navigation”，……。怎么样，都轻车熟路了吧？在 HTML5 中，这些元素都可以换掉。说起新增的语义元素，它们价值的一方面可以这样来体现：“嘿，看啊，这样多好，用 HTML5 新增的元素可以把这些 div 都替换掉。”</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">header</span>&gt;</span>...<span class="tag">&lt;/<span class="name">header</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">nav</span>&gt;</span>...<span class="tag">&lt;/<span class="name">nav</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;main&quot;</span>&gt;</span>...<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">aside</span>&gt;</span>...<span class="tag">&lt;/<span class="name">aside</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">footer</span>&gt;</span>...<span class="tag">&lt;/<span class="name">footer</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br></pre></td></tr></table></figure><p>当然了，你可以这样做。在文档级别上使用这些元素没有问题。但是，假如新增这些元素的目的仅仅是为了取代原来的 div，那就真有点多此一举了。</p><p>虽然在这个文档中，我们用这些新元素来替换的是 ID，但在我个人看来，将它们作为类的替代品更有价值。为什么这么说呢？因为这些元素在一个页面中不止可以使用一次，而是可以使用多次。没错，你可以为文档添加一个头部（header），再添加一个脚部（footer）；但文档中的每个分区（section）照样也都可以有一个头部和一个脚部。而每个分区里还可以嵌套另一个分区，被嵌套的分区仍然可以有自己的头部和脚部，是这样吧？</p><p>这四个新元素：section、article、aside 和 nav，之所以说它们强大，原因在于它们代表了一种新的内容模型，一种 HTML 中前所未有的内容模型——给内容分区。迄今为止，我们一直都在用 div 来组织页面中的内容，但与其他类似的元素一样，div 本身并没有语义。但 section、article、aside 和 nav 实际上是在明确地告诉你——这一块就像文档中的另一个文档一样。位于这些元素中的任何内容，都可以拥有自己的概要、标题，自己的脚部。</p><p>其中最为通用的 section，可以说是与内容最相关的一个。而 article 则是一种特殊的 section。Aside 呢，是一种特殊的 section。最后，Nav 也是一种特殊的 section。</p><p>好，即便是现在，你照样可以使用 div 和类来描述页面中不同的部分，就像下面这样：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;item&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">h2</span>&gt;</span>...<span class="tag">&lt;/<span class="name">h2</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;meta&quot;</span>&gt;</span>...<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;content&quot;</span>&gt;</span>...<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;links&quot;</span>&gt;</span>...<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure><p>其中包含可能是有关内容作者的元数据，而下面会给出一些链接，差不多就这样。在 HTML5 中，我完全可以说这块内容就是一个文档，通过对内容分区，使用 section 或 article 或 aside，我可以说“这一块完全是可以独立存在的。”因此，我当然可以使用 header 和 footer。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">section</span> <span class="attr">class</span>=<span class="string">&quot;item&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">header</span>&gt;</span><span class="tag">&lt;<span class="name">h1</span>&gt;</span>...<span class="tag">&lt;/<span class="name">h1</span>&gt;</span><span class="tag">&lt;/<span class="name">header</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">footer</span> <span class="attr">class</span>=<span class="string">&quot;meta&quot;</span>&gt;</span>...<span class="tag">&lt;/<span class="name">footer</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;content&quot;</span>&gt;</span>...<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">nav</span> <span class="attr">class</span>=<span class="string">&quot;links&quot;</span>&gt;</span>...<span class="tag">&lt;/<span class="name">nav</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">section</span>&gt;</span></span><br></pre></td></tr></table></figure><p>请注意，即便是 footer，也不一定非要出现在下面，不是吗？这几个元素，header、footer、aside、nav，最重要的是它们的语义；跟位置没有关系。一想到 footer 这个词，我们总会不由自主地想，“噢，应该放在下面。”同样，我们把 aside 想象成一个侧边栏。可是，如果你看一看规范，就会发现这些元素只跟内容有关。因此，放在 footer 中的内容也可以是署名，文章作者之类的，它只是你使用的一个元素。这个元素并没有说“必须把我放在文档或者分区的下面。”</p><p>这里，请注意，最重要的还不是我用几个新元素替换了原来的 div 加类，而是我把原来的 H2 换成了 H1——震撼吧，我看到有人发抖了。我碰到过不少职业的 Web 开发人员，多年来他们一直认为规范里说一个文档中只能有一个 H1。还有一些自诩为万能的 SEO 秘诀同样说要这样。很多 SEO 的技巧其实是很教条的。所谓教条，意思就是不相信数据。过去，这种教条表现为“不行，页面中包含两个以上的 H1，你就会死掉的。”在 HTML5 中，只要你建立一个新的内容块，不管用 section、article、aside、nav，还是别的元素，都可以在其中使用 H1，而不必担心这个块里的标题在整个页面中应该排在什么级别；H2、H3，都没有问题。</p><p>这个变化太厉害了。想一想吧，这个变化对内容管理是革命性的。因为现在，你可以把每个内容分区想象一个独立的、能够从页面中拿出来的部分。此时，根据上下文不同，这个独立部分中的 H1，在整个页面中没准会扮演 H2 或 H3 的角色——取决于它在文档中出现的位置。面对这个突如其来的变化，也许有人的脑子会暂时转不过弯来。不要紧，但我可以告诉你，我认为这才是 HTML5 中这些新语义标记的真正价值所在。换句话说，我们现在有了独立的元素了，这些元素中的标题级别可以重新定义。</p><p>我的文档中可能会包含一个分区，这个分区中可能会嵌套另一个分区，或者一篇文章，然后文章再嵌套分区，分区再嵌套文章、嵌套分区，文章再嵌套文章。而且每个分区和文章都可以拥有自己的 H1 到 H6。从这个意义上讲，H 元素真可谓“子子孙孙，无穷匮也”了。但是，在你在编写内容或者内容管理系统的时候，它们又都是独立的，完全独立的内容块。这才是真正的价值所在。<br>实际上，这个点子并不 HTML5 工作组拍脑门想出来的，也不是 W3C 最近才提出来的。下面这几句话摘自蒂姆·伯纳斯 - 李 1991 年的一封邮件，邮件是发给丹·康纳利（Dan Connolly）的。他在邮件中解释了对 HTML 的理解，他说：“你知道……知道我的想法，我认为 H1、H2 这样单调地排下去不好，我希望它成为一种可以嵌套的元素，或者说一个通用的 H 元素，我们可以在其中嵌套不同的层次。”但后来，我们没有看到通用的 H 元素，而是一直在使用 H1 和 H2——那是因为我们一直在支持已有的内容。20 年后的今天，这个理想终于实现了。</p><h2 id="平稳退化"><a href="#平稳退化" class="headerlink" title="平稳退化"></a>平稳退化</h2><p>下一条原理大家应该都很熟悉了，那就是平稳退化。毕竟，我们已经遵守这条规则好多年了。渐进增强的另一面就是平稳退化。</p><p>有关 HTML5 遵循这条原理的例子，就是使用 type 属性增强表单。下面列出了可以为 type 属性指定的新值，有 number、search、range，等等。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;number&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;search&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;range&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;email&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;date&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;url&quot;</span>&gt;</span></span><br></pre></td></tr></table></figure><p>最关键的问题在于浏览器在看到这些新 type 值时会如何处理。现有的浏览器，不是将来的浏览器，现有的浏览器是无法理解这些新 type 值的。但在它们看到自己不理解的 type 值时，会将 type 的值解释为 text。</p><p>无论你写的是 input type&#x3D;”foo”还是 input type&#x3D;”bar”，现有的任何浏览器都会说：“嗯，也许作者的意思是 text。”因而，你从现在开始就可以使用这些新值，而且你也可以放心，那些不理解它们的浏览器会把新值看成 type&#x3D;”text”，而这真是一个浏览器实践平稳退化原理的好例子。</p><p>比如说，你现在输入了 type&#x3D;”number”。假设你需要一个输入数值的文本框。那么你可以把这个 input 的 type 属性设置为 number，然后理解它的浏览器就会呈现一个可爱的小控件，像带小箭头图标的微调控件之类的。对吧？而在不理解它的浏览器中，你会看到一个文本框，一个你再熟悉不过的文本框。既然如此，为什么不能说输入 type&#x3D;”number”就会得到一个带小箭头图标的微调控件呢？</p><p>当然，你还可以设置最小和最大值属性，它们同样可以平稳退化。这是问题的关键。</p><p>再看 input type&#x3D;”search”。你也可以考虑一下这种输入框，因为这种输入框在 Safari 中会被呈现为一个系统级的搜索控件，右边还有一个点击即可清除搜索关键词的 X。而在其他浏览器中，你得到的则是一个文本框，就像你写的是 input type&#x3D;”text”一样，也就是你已经非常熟悉的文本框。那为什么还不使用 input type&#x3D;”search”呢？它不会有什么副作用，没有，对不对？</p><p>HTML5 还为输入元素增加了新的属性，比如 placeholder（占位符）。有人不知道这个属性的用处吗，没有吧？没错，就是用于在文本框中预先放一些文本。不对，不是标签（label）——占位符和标签完全不是一回事。占位符就是文本框可以接受的示例内容，一般颜色是灰色的。只要你一点击文本框，它就消失了。如果你把已经输入的内容全部删除，然后单击了文本框外部，它又会出现。</p><p>使用 JavaScript 编写一些代码当然也可以实现这个功能，但 HTML5 只用一个 placeholder 属性就帮我们解决了问题。</p><p>当然，对于不支持这个属性的浏览器，你还是可以使用 JavaScript 来实现占位符功能。通过 JavaScript 来测试浏览器支不支持该属性也非常简单。如果支持，后退一步，把路让开，乐享其成即可。如果不支持，可以再让你的 JavaScript 来模拟这个功能。</p><p>现在，我不得不提到另一个话题了：HTML5 对 Flash。也许你早听说过了，或者在哪里看到了这方面的讨论。说实话，我一点也不明白。我搞不懂人们怎么会仅仅凭自己的推测来展开争论。<br>首先，他们所说的 HTML5 对 Flash，并不是指的 HTML5，也不是指的 Flash。而是指 HTML5 的一个子集和 Flash 的一个子集。具体来说，他们指的是视频。因此，不管你在哪里听到别人说“HTML5 对 Flash”，那很可能说的只是 HTML5 视频对 Flash 视频。</p><p>其次，一说 HTML5 对 Flash，就好像你必须得作出选择一样：你站在哪一边？实际上不是这样的。HTML5 规范的设计能够让你做到鱼和熊掌兼得。</p><p>好，下面就来看看这个新的 video 元素；真是非常贴心的一个元素，而且设计又简单，又实用。一个开始的 video 元素，加一个结束的 video 元素，中间可以放后备内容。注意，是后备内容，不是保证可访问性的内容，是后备内容。下面就是针对不支持 video 元素的浏览器写的代码：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">video</span> <span class="attr">src</span>=<span class="string">&quot;movie.mp4&quot;</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 后备内容 --&gt;</span> </span><br><span class="line"><span class="tag">&lt;/<span class="name">video</span>&gt;</span></span><br></pre></td></tr></table></figure><p>那么，在后备内容里面放些什么东西呢？好，你可以放 Flash 影片。这样，HTML5 的视频与 Flash 的视频就可以协同起来了。你不用作出选择。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">video</span> <span class="attr">src</span>=<span class="string">&quot;movie.mp4&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">object</span> <span class="attr">data</span>=<span class="string">&quot;movie.swf&quot;</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 后备内容 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">object</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">video</span>&gt;</span></span><br></pre></td></tr></table></figure><p>当然，你的代码实际上并没有这么简单。因为这里我使用了 H264，部分浏览器支持这种视频格式。但有的浏览器不支持。</p><p>对不起，请不要跟我谈视频格式，我一听就心烦。不是因为技术。技术倒无所谓，关键是会牵扯到一大堆专利还有律师、知识产权等等，这些都是 Web 的天敌，对我建网站一点好处都没有。</p><p>可你实际上要做的，仅仅就是把后备内容放在那而已，后备内容可以包含多种视频格式。如果愿意的话，可以使用 source 元素而非 src 属性来指定不同的视频格式。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">video</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">source</span> <span class="attr">src</span>=<span class="string">&quot;movie.mp4&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">source</span> <span class="attr">src</span>=<span class="string">&quot;movie.ogv&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">object</span> <span class="attr">data</span>=<span class="string">&quot;movie.swf&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">&quot;movie.mp4&quot;</span>&gt;</span>download<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">object</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">video</span>&gt;</span></span><br></pre></td></tr></table></figure><p>上面的代码中包含了 4 个不同的层次。</p><ol><li>如果浏览器支持 video 元素，也支持 H264，没什么好说的，用第一个视频。</li><li>如果浏览器支持 video 元素，支持 Ogg，那么用第二个视频。</li><li>如果浏览器不支持 video 元素，那么就要试试 Flash 影片了。</li><li>如果浏览器不支持 video 元素，也不支持 Flash，我还给出了下载链接。</li></ol><p>不错，一开始就能考虑这么周到很难得啊。有了这几个层次，已经够完善了。</p><p>总之，我是建议你各种技术要兼顾，无论是 HTML5，还是 Flash，一个也不能少。如果只使用 video 元素提供视频，难免搬起石头砸自己的脚，我个人认为。而如果只提供 Flash 影片，情况也好不到哪去，性质是一样的。所以还是应该两者兼顾。</p><p>为什么要兼顾这两种技术呢？假设你需要面向某些不支持 Flash 的手持设备——只是举个例子——提供视频，你当然希望手持设备的用户能够看到视频了，不是吗？</p><p>至于为什么要使用不同的格式，为什么 Flash 视频和音频如此成功，我想可以归结为另一个设计原理，即梅特卡夫定律 (Metcalfe’s Law)：</p><blockquote><p>网络价值同网络用户数量的平方成正比。</p></blockquote><p>梅特卡夫的这个定律虽然是针对电话网提出来的，但在很多领域里也是适用的。使用网络的用户越多，网络的价值也就越大。人人都上 Facebook，还不是因为人人都上 Facebook 嘛。虽然 Facebook 真正的价值不在于此，但只有人人都上才会让它的变得如此有价值。</p><p>梅特卡夫定律也适用于传真机。如果只有一个人购买了传真机，当然没有什么用处。但如果其他人也陆续购买了传真机，那么他的投资会就得到回报。</p><p>当然，面对竞争性的视频格式和不同的编码方式，你感觉不到梅特卡夫定律的作用，我也很讨厌以不同的方式来编码视频，但只向浏览器发送用一种方式编码的视频是行不通的。而这也正是 Flash 在视频&#x2F;音频领域如此成功的原因。你只要把 Flash 影片发送给浏览器就好了，然后安装了插件的浏览器都能正常播放。本质上讲，Flash 利用了梅特卡夫定律。</p><h2 id="最终用户优先"><a href="#最终用户优先" class="headerlink" title="最终用户优先"></a>最终用户优先</h2><p>今天我要讲的最后一个设计原理，也是我个人最推崇的一个，但没有要展示的代码示例。这个原理更有哲学的味道，即最终用户优先。</p><p>这个设计原理本质上是一种解决冲突的机制。换句话说，当你面临一个要解决的问题时，如果 W3C 给出了一种解决方案，而 WHATWG 给出了另一种解决方案，一个人这么想，另一个人那么想……这时候，有人站出来说：“对这个问题我们这样来解决。”</p><blockquote><p>一旦遇到冲突，最终用户优先，其次是作者，其次是实现者，其次标准制定者，最后才是理论上的完满。</p></blockquote><p>理论上的完满，大致是指尽可能创建出最完美的格式。标准制定者，指的是工作组、W3C，等等。实现者，指的是浏览器厂商。作者，就是我们这些开发人员，对吧？看看我们在这个链条里面的位置多靠上啊！我们的地位仅次于最终用户——事情本来就该这个样子。用户是第一位的。而我们的声音在标准制定过程中也同样非常非常重要。</p><p>Hixie（即 Ian Hickson，Acid2、Acid3 的作者及维护者，HTML5、CSS 2.1 规范的制定者）经常说，在有人建议了某个特性，而 HTML5 工作组为此争论不下时，如果有浏览器厂商说“我们不会支持这个特性，不会在我们的浏览器中实现这个特性”，那么这个特性就不会写进规范。因为即使是把特性写进规范，如果没有厂商实现，规范不过是一纸空文，对不对？实现者可以拒绝实现规范。</p><p>而根据最终用户优先的原理，我们在链条中的位置高于实现者，假如我们发现了规范中的某些地方有问题，我们想“这样规定我们不能同意，我们不支持实现这个特性”，那么就等于把相应的特性给否定了，规范里就得删除，因为我们的声音具有更高的权重。我觉得这样挺好！本质上是我们拥有了更大的发言权，对吧？我认为开发人员就应该拥有更多的发言权。</p><p>我觉得这应该是最重要的一条设计原理了，因为它承认了你的权利，无论是设计一种格式，还是设计软件，这条原理保证了你的发言权。而这条原理也正道出了事物运行的本质。难道还不够明显吗？用户的权利大于作者，作者的权利大于实现者，实现者的权利大于标准制定者。然而，反观其他规范，比如 XHTML2，你就会发现完全相反的做法。把追求理论的完满放在第一位，而把用户——需要忍受严格错误处理带来的各种麻烦的用户——放在了链条的最底端。我并没有说这种做法就是错误的，但我认为这是一种完全不同的思维方式。</p><p>因此，我认为无论你做什么，不管是构建像 HTML5 这样的格式，还是构建一个网站，亦或一个内容管理系统，明确你的设计原理都至关重要。</p><blockquote><p>软件，就像所有技术一样，具有天然的政治性。代码必然会反映作者的选择、偏见和期望。</p></blockquote><p>下面我们讲一个例子。Drupal 社区曾联系马克·博尔顿（Mark Boulton）和丽莎·雷贺特（Leisa Reichilt）设计 Drupal 的界面。他们计划遵循一些设计原理。为此，他们并没有纸上谈兵，而是经过了一段时间的思考和酝酿，提出指导将来工作的 4 个设计原理：</p><blockquote><p>简化最常见的任务，让不常见的任务不至于太麻烦。<br>只为 80% 设计。<br>给内容创建者最大的权利。<br>默认设置智能化。</p></blockquote><p>实际上，我在跟马克谈到这个问题时，马克说主要还是那两个，即“只为 80% 设计。给内容创建者最大的权利。”这就很不错了，至少它表明了立场，“我们认为内容创建者比这个项目中的任何人都重要。”在制定设计原理时，很多人花了很多时间都抓不住重点，因为他们想取悦所有人。关键在于我们不是要取悦所有人，而是要明确哪些人最重要。他们认为内容创建者是最重要的。</p><p>另一条设计原理，只为 80% 设计，其实是一条常见的设计原理，也是一种通用模式，即帕累托原理（Pareto principle）。</p><p>帕累托是意大利经济学家，他提出这个比例，80&#x2F;20，说的是世界上 20% 的人口拥有 80% 的财富。这个比例又暗合了自然界各个领域的幂律分布现象。总之，无论你是编写软件，还是制造什么东西，都是一样的，即 20% 的努力可以触及 80% 的用例。最后 20% 的用例则需要付出 80% 甚至更多的努力。因此，有时候据此确定只为 80% 设计是很合理的，因为我们知道为此只要付出 20% 的努力即可。</p><p>再比如，微格式同样也利用了帕累托原理，只处理常见用例，而没有考虑少数情形。他们知道自己不会让所有人都满意；而他们的目标也不是让所有人都满意。他们遵循的设计原理很多，也都非常有价值，但最吸引人的莫过于下面这条了：</p><blockquote><p>首先为人类设计，其次为机器设计。</p></blockquote><p>同样，你我都会觉得这是一条再明显不过的道理，但现实中仍然有不少例子违反了这条原理：容易让机器理解（解析）比容易让用户理解更重要。</p><p>所以，我认为平常多看一看别人推崇的设计原理，有助于做好自己手头的工作。你可以把自己认为有道理的设计原理贴在墙上。当然，你可以维护一个 URL，把自己认为有价值的设计原理分享出来，就像 Mozilla 基金会那样，对不对，以下是 Mozilla 的设计原理：</p><blockquote><p>Internet 作为一种公共资源，其运作效率取决于互通性（协议、数据格式、内容）、变革及全球范围内的协作。</p><p>基于透明社区的流程有助于增进协作、义务和信任。</p></blockquote><p>我觉得像这样的设计原理都非常好。而有了设计原理，我认为才更有希望设计出真正有价值的产品。设计原理是 Web 发展背后的驱动力，也是通过 HTML5 反映出来的某种思维方式。我想，下面这条原理你绝对不会陌生：</p><blockquote><p>大多数人的意见和运行的代码。<sup id="fnref:2"><a href="#fn:2" rel="footnote"><span class="hint--top hint--error hint--medium hint--rounded hint--bounce" aria-label="1992 年，大卫·克拉克（David Clark）教授在 IETF 会议上总结了这样一句话“We reject: kings, presidents, and voting. We believe in: rough consensus and running code”（我们拒绝国王、总统和投票，我们相信大多数人的意见和运行的代码）。这就是广为流传的“互联网哲学”（Internet Philosophy）。——译者注">[2]</span></a></sup></p></blockquote><p>对不对？这句话经常在我脑际回响，它囊括了 Web 的真谛，触及了 HTML5 的灵魂。</p><p>也许我该把这条原理打印出来贴到办公室的墙上，让它时刻提醒我，这就是 Web 的设计原理：大多数人的意见和运行的代码。</p><p>我想，今天的演讲就到这里了。如果大家有什么想法可以在 twitter 上通过@adactio 找到我。有时候我也会在自己的博客，adactio.com 上写写有关这个主题的文章。最后，可能还要顺便给我自己做个广告，我刚出了一本书，希望大家关注。</p><p>非常感谢大家。<br>[全文完]</p><div id="footnotes"><hr><div id="footnotelist"><ol style="list-style: none; padding-left: 0; margin-left: 40px"><li id="fn:1"><span style="display: inline-block; vertical-align: top; padding-right: 10px; margin-left: -40px">1.</span><span style="display: inline-block; vertical-align: top; margin-left: 10px;">不清楚博主的这篇翻译文章为什么没了，但原翻译者应该是他没错，这里只进行一下整理<a href="#fnref:1" rev="footnote"> ↩</a></span></li><li id="fn:2"><span style="display: inline-block; vertical-align: top; padding-right: 10px; margin-left: -40px">2.</span><span style="display: inline-block; vertical-align: top; margin-left: 10px;">1992 年，大卫·克拉克（David Clark）教授在 IETF 会议上总结了这样一句话“We reject: kings, presidents, and voting. We believe in: rough consensus and running code”（我们拒绝国王、总统和投票，我们相信大多数人的意见和运行的代码）。这就是广为流传的“互联网哲学”（Internet Philosophy）。——译者注<a href="#fnref:2" rev="footnote"> ↩</a></span></li></ol></div></div>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css&quot;&gt;&lt;p&gt;之所以取个这么大的标题，是因为这是一篇翻译稿的标题。个人认为这篇演讲的翻译稿</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>在计算机学习中，为什么我们应该问为什么</title>
    <link href="https://xinghua.space/2016/03/18/why-should-we-ask-why/"/>
    <id>https://xinghua.space/2016/03/18/why-should-we-ask-why/</id>
    <published>2016-03-18T02:23:14.000Z</published>
    <updated>2024-03-02T07:15:50.690Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css"><p>最近在使用 bootstrap 的时候，遇到一个下拉菜单（dropdown menu）的设计问题。bootstrap 默认的下拉菜单组件是使用 list 作为 html 基础完成的，而不是<code>&lt;select&gt;&lt;/select&gt;</code>。我想这背后一定有设计者的意图，但是对于刚入门前端的我来说很难考究。不过问了一些人之后，发现似乎并没有关注这些实现背后的设计意图问题。</p><p>在之前的一篇博客——<a href="">open questions</a>中，提过一个问题，大意是说在计算机领域，为什么我们要去追问一件事情的动机。最近在学习前端的时候，对这个问题有了更深一步的体会，所以开始将这个问题单独提出来进行阐述。</p><h2 id="科学哲学中的「四因说」"><a href="#科学哲学中的「四因说」" class="headerlink" title="科学哲学中的「四因说」"></a>科学哲学中的「四因说」</h2><p>早在古希腊时代，就有哲学家开始思索事物的本质了。有一个很有名的哲学家提出了一些解释事物运动与变化的论点，其核心思想也就是标题中所描述的<a href="https://zh.wikipedia.org/wiki/%E5%9B%9B%E5%9B%A0%E8%AA%AA">「四因说」</a>。当然，如你所料，这位哲学家的名字叫「亚里士多德」。</p><p>为了省去时间解释「四因说」的概念，摘出吴国盛老师博客：<a href="https://blog.sina.com.cn/s/blog_51fdc06201009s7z.html">海德格尔的技术哲思</a>中的几段话来稍作说明，当然你也可以参考英文版的维基百科词条，或者是更专业的科哲书籍：</p><blockquote><p>导致一个物出现的东西被称为该物的原因。亚里士多德曾经主张原因有四种，即「质料因」、「形式因」、「目的因」和「动力因」。比如造一顶皇冠，金子是它的质料因；皇冠的形状是它的形式因；皇帝用来举行大典、显示威仪和华贵是它的目的因；工匠汇总各方面的要求和准备并发挥自己的作用从而最终将皇冠拿出来，工匠是它的动力因。</p><p>今日我们对这四因说不是太理解，不知道为什么要提出四种原因，更不知道为什么单单提出这四种原因。因为当我们说到“原因”时，指的往往只是那直接产生作用并造成和带来最终结果的东西，也就只是亚里士多德意义上的动力因（也可以称之为「直推因」 ——引用注）。皇冠作为被造出来的结果，在我们今天看来，工匠是其唯一的原因。</p><p> 动力因成为四因中起决定作用的方面，并最终决定了对因果性的规定。这件事情发生在 16、17 世纪之后 (也就是机械自然观开始成型的那些年 ——引用注)，非同寻常，里面包含着近代思想对于目的因的排除。一个物的出现被描述为另一个早先的物加上某个作用力的结果，物在某种意义上成了现成的东西，即所谓“物质”。物不再“出现”（coming to），它根本就在场，恒久的在场。因果性说的也不再是那种使物“出现”的东西，而是根本上在场的物质的在数量方面的变化。<br> 这种对因果性的规定使我们无法理解希腊人的四因说，特别是，使我们对希腊人四因说中的动力因的理解打上我们时代的烙印：对物产生作用，使其发生改变。但是那种希腊意义上四因之间的内在联系就完全丢失了。海德格尔提醒说，对工具之本质的理解依赖于对因果性之本质的理解，而对因果性的本质我们至今还茫然无知，这一茫然无知特别表现在我们对希腊四因说的误解</p></blockquote><p>上面的吴老师的文字，基本上已经很清楚的解释了什么是「四因说」以及为什么在今天我们提到一件事情的「原因」时，我们暗示的语境是「一个原因（cause）」而不是「四个原因（cause）」。这是因为 16，17 世纪发生的自然观的范式转变造成的，这些转变把四因说中的「动力因」（也可以说是直推因）当成事物变化的首要因素，以及「四因说」中的其他几个原因被淡化了。</p><h2 id="动力因（直推因）——-传统自然科学探究的有效方式"><a href="#动力因（直推因）——-传统自然科学探究的有效方式" class="headerlink" title="动力因（直推因）—— 传统自然科学探究的有效方式"></a>动力因（直推因）—— 传统自然科学探究的有效方式</h2><p>在传统科学中，我们说一件事情的原因的时候，往往指的就是它的直推因。比如曾经在知乎上回答的一个问题：<a href="https://www.zhihu.com/question/30546364/answer/50020320">为啥乙醇没毒，而甲丙丁醇都有毒？</a></p><p>然后可以观察下面的答案，得票最高的答案描述了醇类的分子结构以及相应的化学性质，不同醇类在人类体内所产生的不同影响，并且给出了相当专业的答案。从这种角度出来，所阐述的就是「醇类毒性的直推因」。也就说「当前是什么样」。</p><p>在科学革命之后，上述回答中体现出的思想一直是自然科学研究的指导思想。这种追问「直推因」的研究模式有非常巨大的优势：它可以引导人类先将那些最根本的追问放到一旁，集中精力研究在当前阶段下能研究的东西，对于不能研究的或者研究暂时够不着的地方保持沉默。比如研究物体的运动，最直接的是去研究推动物体的力，研究在不同力的作用下，产生的不同效果。同时将牛顿所讲的第一推动力放到一旁，暂时不予考虑。正是这样按照一种内在的逻辑精密的步步前行，不断积累，并且如我们所见，这种研究形式取得了重大的成果。</p><p>但是这并没有给「我们的期待」一个显得更更本质的解释：对，这个答案说的是非常准确，非常符合人类目前掌握的生理化学知识，但是仍然可以在这个基础上问一句，为什么是这样？是什么原因造成了生理化学上的这种现状？</p><h2 id="目的因-——-我们的期待"><a href="#目的因-——-我们的期待" class="headerlink" title="目的因 —— 我们的期待"></a>目的因 —— 我们的期待</h2><p>正如上面小结结尾所提出的问题，我们人类心理上总是想要一种「更为本质」的解释，而且有些偏执的认为这种「更为本质的解释应该存在」，虽然目前来看很多都只是「因果关系上的错觉」。这一点在达尔文的进化论中表现的更为明显，正如我在：为啥乙醇没毒，而甲丙丁醇都有毒？问题下的回答。</p><blockquote><p>这题明显是一个生理学加进化论的问题，一旦牵扯到进化论，「因果关系」就会变得微妙起来。</p><p>我们说一件事物「有毒」的时候，是暗含着语境的——对生物来说。甲乙丙丁醇，结构相似，为什么乙醇毒性最小？从生理化学方面回答，只能回答出这种毒性表现「是什么」，从因果关系上讲，这样推理找到的是“有毒”的「直推因」。</p><p>「直推因」是指与所要研究的事情本身最直接的原因。探寻直推因也是物理和化学中最常见的研究形式。这个来历与十六七世纪发生的科学革命有很大关系，具体情况比较复杂，这里不细说。</p><p>但是在生物学上，只研究直推因，能很好的说明“表现为什么样，是什么样”，但并不能很好的说明“为什么是这样”。在回答「是什么样」的时候，生理化学做的很好了。至于「为什么这样」，只能求助于进化论。</p><p>大胆的猜测就是因为：乙醇在自然条件下更容易出现 (至于为什么更容易出现，又是另一个问题了)，生命接触乙醇的机会比其他醇类多。这样就导致了生命对于乙醇的不敏感。</p><p>至于证据问题，只能说这个猜测和进化论的逻辑是相符合的。如果要拿出具体的数据很难。</p><p>这个答案的正确性暂且不论，而且关于进化论中令人头疼的因果关系也姑且不去考虑，我想说的就是即便是上面这样的「半吊子目的因答案」也会给我们一种：『吖，就是这样！』的感觉，仿佛满足了我们灵魂最深处的某种渴望一样。</p><p>其实这就是「目的因」的魅力——它满足我们人类某种对真相的神秘渴求。即便有时候这种目的因是虚妄的。</p></blockquote><h2 id="计算机科学中的「目的因」"><a href="#计算机科学中的「目的因」" class="headerlink" title="计算机科学中的「目的因」"></a>计算机科学中的「目的因」</h2><p>上面讲述了传统自然科学中的研究或者学习方式。但是对于计算机科学来说却不是这样。在自然界内，各种事物都是独立于人类存在的，多数事物更是早早先于人类就存在无数年头了，我们很难甚至可以说基本没有办法追溯回去，看看当初事物出现时的样子，以及在自然界这个复杂系统中所处的位置。</p><p>但在计算机领域内却大不一样，有非常多的内容是「人类创造的」，这些内容出于某些动机而构建出来，非常符合人类的直觉——这么干，背后肯定有一种「更为本质的原因」，而这种本质的原因，就是创造者的目的和意图。</p><p>这些现象基本上可以推广到所有与人造事物有关的事物上去。我们设计或者创造一种事物，都是有着某种根植于当时环境的目的在里面的。以一个普通桌子椅子为例，每一种设计，都有创造者背后想要表达的目的，它们都不是凭空出现的，而是伴生着创造者所种下的意向而来。有折叠的椅子，那设计师考虑的可能是节省空间，有纯榫卯的椅子，那可能是创造者为了自然环保，或者追溯往日的情怀。</p><p>在计算机领域，我们同样应该追问一件事情的「目的因」，也就是这件事物背后创造者的初衷。通过追问这些初衷可以更加了解一件事物内在的意向，以及深化对于这件事物的认识。比如设计模式，为什么要有这些设计模式，有没有其他的？当我们了解到这些之后，就会意识到这些东西不是铁板一块，进而解放我们的创造力。</p><h2 id="前端领域"><a href="#前端领域" class="headerlink" title="前端领域"></a>前端领域</h2><p>在前端领域更是如此，前端纯粹是人类建构出来的，我们可以追问许多东西，比如 html5 的作用是什么？为什么提出 html5，提出者们是怎么考虑的？</p><p>通过这些追问，可以让我们根据问题回溯到设计者的意图上去，了解初衷，从而产生更深入的理解以及对未来的把握。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css&quot;&gt;&lt;p&gt;最近在使用 bootstrap 的时候，遇到一个下拉菜单（dropdown </summary>
      
    
    
    
    <category term="作为工程师" scheme="https://xinghua.space/categories/%E4%BD%9C%E4%B8%BA%E5%B7%A5%E7%A8%8B%E5%B8%88/"/>
    
    
  </entry>
  
  <entry>
    <title>隐喻</title>
    <link href="https://xinghua.space/2016/02/26/metaphor/"/>
    <id>https://xinghua.space/2016/02/26/metaphor/</id>
    <published>2016-02-26T02:13:33.000Z</published>
    <updated>2024-03-02T07:12:18.685Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css"><h2 id="隐喻"><a href="#隐喻" class="headerlink" title="隐喻"></a>隐喻</h2><h3 id="为什么明确概念如此重要"><a href="#为什么明确概念如此重要" class="headerlink" title="为什么明确概念如此重要"></a>为什么明确概念如此重要</h3><p>在美剧中，我们常常能见到演员们提及或使用「隐喻」这种修辞手法，而且模糊的知道这种修辞和「类比」相似，但是缺少对这种修辞的清晰认知。实际上，我们平时日常交谈时，常常会无意识的使用到这种修辞，而造成这种无意识的原因是我们对「隐喻」没有一个明确的概念。</p><p>不止隐喻是这样，在日常生活中，常常会遇到这样的情景：在你明确一件事物的概念之前，即使这件事物在身边常常见到，你也不会过多的去留意它，这个时候对这件事物的认知，就处于一种「无意识」的状态，而你一旦掌握了这样事物的概念之后，就会脱离那种混沌的无意识状态，转而开始有意的留意身边的这些事物，就会吃惊的发现，啊，原来它早已存在。</p><p>用一个比较哲学的说法，这叫「有之非有，存在的无」。人类根据经验在语言上建立起一种事物的概念，然后这个语言学上的概念，反过来又会促进人类更加留意对应的事物，最终加深对概念和事物更深刻的认识。</p><p>在《写给大家看的设计书》中，作者开篇就写了约书亚树的例子。</p><blockquote><p>约书亚树</p><p>很多年前的一个圣诞节，我收到一份圣诞礼物，是一本关于如何认识各种树的书。那时我住在父母的家里，所有礼物都打开后，我决定出去走走，认一认邻居家的树。出去之前我读了书的一部分。其中提到的第一种树是约书亚树，只需要两个线索就能认出它。由于约书亚树相当怪异，所以看到书中它的照片时，我对自己说：“哦，北加利福尼亚绝对没有这种树。这种树太怪异了。如果我见过，肯定应该有印象，可我以前从来没有见过。”</p><p>之后我拿着这本书走出去。我的父母住在一个小巷子里，这里共有 6 家住户。其中 4 家的前院里都赫然立着约书亚树。我住在那里已经有 13 年了，而我此前从来没有注意过约书亚树。我在这个街区转了转，发现似乎每一家布置新居时苗圃里都有约书亚树卖，至少 80% 的住家前院都种有约书亚树。而我在此之前居然从来没有注意过！在我知道了这种树之后，我是说在我能够说出它的名字后，它就无处不在了。这正是我要说的：一旦能够说出什么东西的名字，就会很容易注意到它。你就会掌握它，拥有它，使它在你的控制中。</p></blockquote><p>这个例子所讲述的内容并不是特殊的情况，它背后有着关于语言和认知的更深层次的问题。概念是思维的最基本单元，其重要性我们怎样重视都不会过分。现在有一些认知，语言上的方向专门来研究这些问题，而本文就简单介绍「隐喻」的概念，以及讲述在计算机科学中「隐喻」的重要性。</p><p>原本对隐喻的介绍是在其他文章中完成的，但是后来越来越感觉到这个概念的重要性，以至于不得不单独提出来特别讲述一下。就如前面所描述，一旦「隐喻」的概念明确之后，你就会开始摆脱原来的无意识使用状态，有意识地使用这种修辞来表达一些原来难以言状的概念，事物等。而且也会发现，「隐喻」这种修辞随处可见，并且深刻意识到它带来的好处。</p><h3 id="《代码大全》对隐喻的态度"><a href="#《代码大全》对隐喻的态度" class="headerlink" title="《代码大全》对隐喻的态度"></a>《代码大全》对隐喻的态度</h3><p>在《代码大全》中，作者在欢迎章节之后，就开始介绍软件开发中的隐喻，并且强调了隐喻的重要性：</p><blockquote><p>计算机科学领域中有着所有学科中最为丰富多彩的语言。你走进一间安全严密，温度精确控制在 20℃的房间，并在里面发现了病毒（virus），特洛伊木马（Trojan horse），蠕虫（worm），臭虫（bug），逻辑炸弹（bomb），崩溃（crash），论坛口水战（flame），双绞线转换头（twisted sex changer），还有致命错误（fatal error）……在其他领域中，你能遇到这些吗？</p></blockquote><p>这些形象的隐喻描述了软件领域总各种特定的现象和事物，像这样生动活泼的隐喻还能够描述更加广泛的现象。借助这些隐喻，我们能更深刻的理解软件开发的过程。</p><h2 id="那么什么是隐喻？"><a href="#那么什么是隐喻？" class="headerlink" title="那么什么是隐喻？"></a>那么什么是隐喻？</h2><p>隐喻是比喻的一种，其字面意思是「隐含的比喻」。与普通的比喻，也就是「明喻」相对。</p><p>对比来讲，明喻这种修辞手法在日常用语中是使用最多的比喻形式，例如「貌美如花」，「父爱如山」等。使用「明喻」主要是因为某些审美上的倾向，希望将一种事物上的审美特点添加到另一种事物上，比如上面的词语中，想要将花朵的美好赋予到人类身上，或是将山的厚重，巍峨的特性赋予到父亲身上。</p><p>而「隐喻」则有所不同，它多数不是因为审美上的倾向才使用，而是想要表达出两种事物之间有某种实实在在的联系。比如莎士比亚的著名隐喻：</p><blockquote><p>All the world’s a stage,<br>And all the men and women merely players;<br>They have their exits and their entrances. and one man in his time plays many parts…<br>—William Shakespeare</p><p>世界是舞台，男人和女人都是演员。他们都有下场的时候，也都有上场的时候。一个人的一生中扮演着好几个角色。<br>——莎士比亚</p></blockquote><p>莎士比亚使用这个隐喻，并不是想将舞台和演员某些审美上的特点赋予世界和人类，而是实实在在的认为，世界的运行机制和舞台剧的运行机制，有某些相似点。</p><p>很多人（通常是认知语言学家）认为，「隐喻」这种修辞具有认知学上的意义。换句话说，它可以帮助人类更好的认识一件事物，所使用的手段就是将一种比较新的陌生的概念，与已知的比较容易理解的其他概念联系起来，利用两件事物之间的相似性辅助认知。</p><h2 id="一些例子——那些我们曾注意或不曾注意的隐喻"><a href="#一些例子——那些我们曾注意或不曾注意的隐喻" class="headerlink" title="一些例子——那些我们曾注意或不曾注意的隐喻"></a>一些例子——那些我们曾注意或不曾注意的隐喻</h2><p>在语言中，一种新事物的产生需要一个词汇来命名时，一种手段是在原来有的词汇的基础上进行引申，而这种引申并不是随性而为的，往往是新事物之间和之前的旧事物之间有某些特殊的相似性。</p><p>一些典型的例子：</p><ul><li>socket：原意是插头，插座。在计算机通信传输时，引申为一种信息交互的机制。特点就像是插座那样，有对接的意思。</li><li>docker：原意是码头工人。现在出现了一种常用的虚拟化技术，叫 docker。它同样借助了码头工人，集装箱一类的隐喻，来表达标准化交付的意思。</li><li>待续</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css&quot;&gt;&lt;h2 id=&quot;隐喻&quot;&gt;&lt;a href=&quot;#隐喻&quot; class=&quot;headerli</summary>
      
    
    
    
    <category term="随笔" scheme="https://xinghua.space/categories/%E9%9A%8F%E7%AC%94/"/>
    
    
  </entry>
  
  <entry>
    <title>问题记录</title>
    <link href="https://xinghua.space/2016/02/25/questions-record/"/>
    <id>https://xinghua.space/2016/02/25/questions-record/</id>
    <published>2016-02-25T01:25:29.000Z</published>
    <updated>2024-03-02T07:14:23.789Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css"><p>Meta: 本文章用来记录平时遇到的问题以及相应的解决方案</p><h2 id="杂项"><a href="#杂项" class="headerlink" title="杂项"></a>杂项</h2><h3 id="linux-crontab-django-command-定时执行命令"><a href="#linux-crontab-django-command-定时执行命令" class="headerlink" title="linux crontab + django command 定时执行命令"></a>linux crontab + django command 定时执行命令</h3><h4 id="问题场景"><a href="#问题场景" class="headerlink" title="问题场景"></a>问题场景</h4><p>在做一个档案管理系统时，有一个需要定时从 DB2 数据库中取出数据，处理之后，存入 mysql 中的任务。这意味着需要在 django 中单独跑一个脚本，这个脚本使用 django 的环境。</p><h4 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h4><p>django 提供了一种用户自定义命令来实现这个功能：</p><blockquote><p><a href="https://docs.djangoproject.com/en/1.9/howto/custom-management-commands/">Writing custom django-admin commands¶</a></p></blockquote><p>而 linux 则提供了定时执行任务方面的好用工具：</p><blockquote><p><a href="https://linuxtools-rst.readthedocs.io/zh-cn/latest/tool/crontab.html">linux crontab</a></p></blockquote><h3 id="往-mysql-中写大量数据时，出现错误：2006‘mysql-server-has-gone-away’"><a href="#往-mysql-中写大量数据时，出现错误：2006‘mysql-server-has-gone-away’" class="headerlink" title="往 mysql 中写大量数据时，出现错误：2006‘mysql server has gone away’"></a>往 mysql 中写大量数据时，出现错误：2006‘mysql server has gone away’</h3><h4 id="问题场景-1"><a href="#问题场景-1" class="headerlink" title="问题场景"></a>问题场景</h4><p>在做一个档案管理系统时，使用 django+mysql，当一次性往 mysql 中写入了近 3w 条数据时，就出现了这个错误</p><h4 id="解决方案-1"><a href="#解决方案-1" class="headerlink" title="解决方案"></a>解决方案</h4><p>调查发现是因为 mysql 默认的有一个写入数据大小限制。只需要在<code>/etc/my.cnf</code>(如果没有这个文件就自己建立一个) 下加上下面的代码即可</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">[mysqld]</span><br><span class="line">max_allowed_packet = 16M</span><br></pre></td></tr></table></figure><p>当然，也可以限制一下自己每次往 mysql 中写入数据的数量来解决这个问题。</p><h3 id="vim-分屏与-ctrl-p-插件"><a href="#vim-分屏与-ctrl-p-插件" class="headerlink" title="vim 分屏与 ctrl p 插件"></a>vim 分屏与 ctrl p 插件</h3><p>之前总是听说 <code>ctrl p</code> 插件如何如何好用。不过我开始试用的时候，确实没有体会到太强大的地方，知道后来发现 vim 的分屏功能。</p><p>试用 vim 分屏功能，加上 ctrl p 实现了不退出 vim 直接打开多个文件的功能，节省了大量在命令行下各种 cd 目录 的时间。</p><p>参考：<a href="https://coolshell.cn/articles/1679.html">Vim 的分屏功能</a></p><h3 id="基础正则表达式"><a href="#基础正则表达式" class="headerlink" title="基础正则表达式"></a>基础正则表达式</h3><p>有一次，我需要在一个包含很多行短文字的后面补上的空格，将每一行补成相同的宽度。<br>刚开始使用各种列编辑，块编辑尝试都没有用。难道必须写一个程序来专门处理这件事情？</p><p>后来发现正则表达式基本能满足这一要求：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_">%</span><span class="language-bash">s/$/ n_spaces /g</span></span><br><span class="line">```    </span><br><span class="line"></span><br><span class="line">在 vim 中，$符有丰富的含义，这里指的是行尾前一个字符</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash"><span class="comment"># 前端</span></span></span><br><span class="line">主要记录一下前端学习中遇到的容易混淆的地方，个人感觉在 html，css 和 javascript 中。当属 css 最令人难以捉摸，由于浏览器默认样式或是限制，css 继承，层叠规则等的存在，综合作用之下，很多时候都觉得 css 效果与预期不一致。因此 css 的内容或许会更多一些。</span><br><span class="line">仅仅是零散的记录，暂时没有整理成单独文章的精力。以后或许会把一些可以扩展的地方扩展成文章式的内容。</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash"><span class="comment">## CSS 伪类和伪元素区别</span></span></span><br><span class="line">伪类：Pseudo-elements</span><br><span class="line">伪元素：Pseudo-classes</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash"><span class="comment">### 概念辨析</span></span></span><br><span class="line">stackoverflows 上的回答</span><br><span class="line">[What is the difference between a pseudo-class and a pseudo-element in CSS?](https://stackoverflow.com/questions/8069973/what-is-the-difference-between-a-pseudo-class-and-a-pseudo-element-in-css)</span><br><span class="line"></span><br><span class="line">W3C 上的说明</span><br><span class="line">[pseudo-elements](https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#pseudo-elements)</span><br><span class="line">[pseudo-classes](https://www.w3.org/TR/2011/REC-css3-selectors-20110929/#pseudo-classes)</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash"><span class="comment">## CSS font-size 相对大小继承</span></span></span><br><span class="line">font-size 使用 em 等相对大小时，会发生计算叠加。</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">&gt; </span><span class="language-bash">摘自《css 设计指南》</span></span><br><span class="line"><span class="meta prompt_">&gt; </span><span class="language-bash"></span></span><br><span class="line"><span class="language-bash">&gt; 一般来说，em 以浏览器默认值为基本单位，也就是 1em=16px。如果你想使用 em，但又需要设定具体的像素大小，可以把 body 的 font-size 设定为 62.5%。这样，就等于把基准大小从 16 像素改为 10 像素 (16×62.5%=10)。然后，em 与像素的对应关系就十分明确了，比如 1em 等于 10 像素，1.5em 等于 15 像素，2em 等于 20 像素，等等。</span></span><br><span class="line"><span class="meta prompt_">&gt; </span><span class="language-bash"></span></span><br><span class="line"><span class="language-bash">&gt; p 元素的文本为 12 像素 (body 的 16 像素基准大小×.75=12px), strong 是 p 的子元素，它的文本相对大小会逐层复合，应该是 16px 0.75 0.75=9px。</span></span><br><span class="line"></span><br><span class="line">**注意与 text-indent 的区别：** font-size 会叠加复合计算，text-indent 则是后面的值覆盖前面的值</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">&gt; </span><span class="language-bash">text-indent 可以被子元素继承。如果你 在一个 div 上设定了 text-indent 属性，那么 div 中的所有段落都会继承该缩进值。然而，与 所有继承的 CSS 值一样，这个缩进值并不是祖先元素中设定的值，而是计算的值。下面举一个 例子说明。</span></span><br><span class="line"><span class="meta prompt_">&gt; </span><span class="language-bash"></span></span><br><span class="line"><span class="language-bash">&gt; 假设有一个 400 像素宽的 div，包含的文本缩进 5%,则缩进的距离是 20 像素 (400 的 5%)。在这个 div 中有一个 200 像素宽的段落。作为子元素，它继承父元素的 text-indent 值，所以 它包含的文本也缩进。但继承的缩进值是多少呢？不是 5%,而是 20 像素。也就是说，子元素 继承的是根据父元素宽度计算得到的缩进值。结果，虽然段落只有父元素一半宽，但其中的文 本也会缩进 20 像素。这样可以确保无论段落多宽，它们的缩进距离都一样。当然，在子元素 上重新设定 text-indent 属性，可以覆盖继承的值。</span></span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash"><span class="comment">## inline-block 的表现</span></span></span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">&gt; </span><span class="language-bash">This value causes an element to generate an inline-level block container. The inside of an inline-block is formatted as a block box, and the element itself is formatted as an atomic inline-level box.</span></span><br><span class="line"><span class="meta prompt_">&gt; </span><span class="language-bash">大致意思就是：inline-block 后的元素创建了一个行级的块容器，该元素内部（内容）被格式化成一个块元素，同时元素本身则被格式化成一个行内元素。</span></span><br><span class="line"><span class="meta prompt_">&gt; </span><span class="language-bash"></span></span><br><span class="line"><span class="language-bash">&gt; 直白一点的意思就是：inline-block 的元素既具有 block 元素可以设置宽高的特性，同时又具有 inline 元素默认不换行的特性。当然不仅仅是这些特性，比如 inline-block 元素也可以设置 vertical-align 属性。简而言之：</span></span><br><span class="line"><span class="meta prompt_">&gt; </span><span class="language-bash">inline-block 后的元素就是一个格式化为行内元素的块容器 ( Block container )</span></span><br><span class="line"></span><br><span class="line">疑问：</span><br><span class="line"></span><br><span class="line">inline-block 的 margin 边距会撑开父元素的高度，而普通的 block 的边距则会与父元素的 margin 边距重合？</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">参考：</span><br><span class="line">[inline-block 前世今生](http://ued.taobao.org/blog/2012/08/inline-block/)</span><br><span class="line"></span><br><span class="line">[w3c: the ‘display’ property](https://www.w3.org/TR/CSS2/visuren.html#display-prop)</span><br><span class="line"></span><br><span class="line">[mozilla: vertical-align](https://developer.mozilla.org/en-US/docs/Web/CSS/vertical-align)</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash"><span class="comment">## rem 使用</span></span></span><br><span class="line">今天在 chrome 中实验 rem 相对单位，刚开始的实验代码为：</span><br><span class="line"></span><br><span class="line">```html</span><br><span class="line">&lt;!DOCTYPE html&gt;</span><br><span class="line">&lt;html&gt;</span><br><span class="line">&lt;head&gt;</span><br><span class="line">&lt;meta charset=&quot;utf-8&quot;&gt;</span><br><span class="line">&lt;title&gt;test rem&lt;/title&gt;</span><br><span class="line">&lt;style type=&quot;text/css&quot;&gt;</span><br><span class="line">html&#123;</span><br><span class="line">font-size: 62.5%;  // 这里的表现有点奇怪</span><br><span class="line">&#125;</span><br><span class="line">body&#123;</span><br><span class="line">font-size: 1.2rem;</span><br><span class="line">&#125;</span><br><span class="line">div&#123;</span><br><span class="line">width: 300px;</span><br><span class="line">height: 300px;</span><br><span class="line">background-color: red;</span><br><span class="line">padding: 1rem;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/style&gt;</span><br><span class="line">&lt;/head&gt;</span><br><span class="line">&lt;body&gt;</span><br><span class="line">&lt;p&gt;测试字体大小&lt;/p&gt;</span><br><span class="line">&lt;div&gt;&lt;/div&gt;</span><br><span class="line">&lt;/body&gt;</span><br><span class="line">&lt;/html&gt;</span><br></pre></td></tr></table></figure><p>但是这个时候，font-size 并不是 10px，之前在网上看到将 root 元素的 font-size 设置为 10px，方便后文计算。但是在这里似乎并没有起到效果。</p><p>原因是因为 chrome 默认所允许的最小字体为 12px，如果设定值小于此值，就会被重置成 12px。这个时候，<code>1rem=12px</code>，关于 chrome 最小字体限制，</p><p>参考：<a href="https://banri.me/web/webkit-text-size-adjust.html">Chrome 取消-webkit-text-size-adjust 后的那些事</a></p><h3 id="块级元素和行内元素"><a href="#块级元素和行内元素" class="headerlink" title="块级元素和行内元素"></a>块级元素和行内元素</h3><ul><li>块级元素（block level element）<ul><li>独占一行</li><li>可设置 width，height</li><li>默认</li></ul></li><li>内联元素（inline element）<ul><li>设置 width height 无效</li></ul></li></ul><p>参考：<a href="https://geekplux.com/posts/several_core_concepts_of_css.html">CSS 最核心的几个概念</a></p><h3 id="width-和-height"><a href="#width-和-height" class="headerlink" title="width 和 height"></a>width 和 height</h3><p>定义元素「内容区」的宽度，默认值为 auto 无继承性。浏览器会计算出实际的宽度。</p><p>height 和 width 实用百分数相对单位时，相对的是父元素宽度计算（父元素的宽度同理）。如果不指定，默认值就是图片本身的宽高，如果图片加载失败，会显示 alt 属性值，或者浏览器自带的加载失败效果。</p><h3 id="各种居中方法的使用场景"><a href="#各种居中方法的使用场景" class="headerlink" title="各种居中方法的使用场景"></a>各种居中方法的使用场景</h3><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">// 水平居中</span><br><span class="line">// 使用 <span class="attribute">margin</span> 水平居中元素的时候，</span><br><span class="line">// 需要指定要居中元素的 <span class="attribute">width</span> 值（与父元素的宽度无关）</span><br><span class="line">// 显然这里只适用于块级元素</span><br><span class="line">// 居中被设置该属性的元素自身，不是子元素，也不是父元素 </span><br><span class="line"><span class="attribute">margin</span>: <span class="number">0</span>, auto;   </span><br><span class="line"><span class="attribute">text-align</span>： center</span><br></pre></td></tr></table></figure><h3 id="如果内部盒大小超出了外部盒所能包含的大小时表现会如何"><a href="#如果内部盒大小超出了外部盒所能包含的大小时表现会如何" class="headerlink" title="如果内部盒大小超出了外部盒所能包含的大小时表现会如何"></a>如果内部盒大小超出了外部盒所能包含的大小时表现会如何</h3><h2 id="使用过的工具"><a href="#使用过的工具" class="headerlink" title="使用过的工具"></a>使用过的工具</h2><ul><li>reactjs react router</li><li>underscore</li><li>project-path（npm 模块）</li><li>fixed-data-table（react 组件）</li></ul><h2 id="程序中的过度设计"><a href="#程序中的过度设计" class="headerlink" title="程序中的过度设计"></a>程序中的过度设计</h2><h3 id="什么是程序中的过度设计"><a href="#什么是程序中的过度设计" class="headerlink" title="什么是程序中的过度设计"></a>什么是程序中的过度设计</h3><p>所谓过度设计或者过度工程，顾名思义就是在编写代码的时候，过多的假想了一些本来不存在的场景，并且在这些假想的场景中做出对应的设计，比如处处考虑将来可能出现的变动等等。而实际上，这个时候代码离考虑这些还有很远的距离。</p><h3 id="我遇到的过度设计"><a href="#我遇到的过度设计" class="headerlink" title="我遇到的过度设计"></a>我遇到的过度设计</h3><p>在之前开发产品的时候，实际上在有些地方过度强调了将来可能面临的风险或变动，比如产品中的图片采用 qiniu 云存储，刚开始存储的统一都是 url，但是这时候工程师假想了一个场景：「如果将来七牛的域名改变了，或者将来不适用七牛了怎么办？」然后将原来的统一 url 改为 key，但是发现实际的改写操作并不是一件容易的事情，最后只好作罢。</p><p>另一件事情则是产品中的过度设计，在我们开发一个产品的时候，产品经理给出的产品原型变动了无数次，最后的一些变动甚至改变了最基本的数据信息，导致之前写的代码完全失效。而这个产品正是一个需要快速迭代的产品，直到现在第一版还没有做出来。其实这个例子不能算是过度设计，姑且写在这里吧。</p><p>不清楚经常强调 mvp(minimum viable product，最小化可行产品) 的我们，为何在做自己的产品的时候，却完全不予考虑了。</p><p>当然对于编程经验还不够丰富的我来说，考虑这些还为时尚早，暂且先记录下来，以待将来反思。</p><h2 id="产品体验"><a href="#产品体验" class="headerlink" title="产品体验"></a>产品体验</h2><h3 id="iOS-初体验"><a href="#iOS-初体验" class="headerlink" title="iOS 初体验"></a>iOS 初体验</h3><p>最近服役了三年的 nexus 终于老态龙钟，光荣退伍了。纠结于 android 的多种多样，最终直接选了 iphone。一上手就感觉有几个地方特别的别扭，这里面自然有一些不同系统之前切换带来的生疏感，但是有些地方明显是设计有问题。</p><h4 id="鸡肋的下拉菜单"><a href="#鸡肋的下拉菜单" class="headerlink" title="鸡肋的下拉菜单"></a>鸡肋的下拉菜单</h4><p>对比 Android 强大的下拉菜单，iOS 的下拉菜单仅用于消息通知或是近期使用的软件功能，而将一部分设置放在了从底部向上拉的菜单中，即便是这些设置也是不完整的，比如 wifi 设置，只能设定开关，而不能由此作为入口进一步设置 wifi。如果想设置 wifi 需要去设置页中去找。</p><p>再来看 Android 的下拉菜单设置，不管是 wifi 还是手电筒等功能，都无比的实用与方便，而且使用频率很高。</p><h4 id="捉急的闹钟设置"><a href="#捉急的闹钟设置" class="headerlink" title="捉急的闹钟设置"></a>捉急的闹钟设置</h4><p>这个就更明显了，android 的闹钟设置一步到位。而 iOS 的闹钟设置页面，要先点击左上角的编辑，进入编辑页，再点击时间才能选择。一步能完成的功能愣是给拆成了好几个步骤。用的时候简直无比纠结。</p><h4 id="难以捉摸的输入法和全局赋值粘贴"><a href="#难以捉摸的输入法和全局赋值粘贴" class="headerlink" title="难以捉摸的输入法和全局赋值粘贴"></a>难以捉摸的输入法和全局赋值粘贴</h4><p>九宫格输入法中的各个按键占比无比蛋疼，主要区域占比不够，而一个大大的确认按钮放在了右侧，占据了 n 多面积。</p><p>再者是输入法和全局复制粘贴的表现简直匪夷所思，它们的各种表现简直难以寻找规律。感觉一会儿是这样，一会儿是那样。</p><h4 id="没有充分利用触屏优势的短信界面"><a href="#没有充分利用触屏优势的短信界面" class="headerlink" title="没有充分利用触屏优势的短信界面"></a>没有充分利用触屏优势的短信界面</h4><p>ios 短信界面的编辑功能，仍然是左上角有一个编辑按钮，点击之后才能进行编辑。而触摸短信只能进入短信详情，长触摸则没有响应动作。</p><p>「编辑按钮」这个功能在 iOS 中随处可见，诸如上面提到的闹钟编辑。这和 Android 有很大的区别，在 Android 中，长触摸一般都表示对触摸项的编辑功能。而 iOS 则没有为长触摸指定动作。这样就又多出一步。实在是没有充分利用触屏本身的交互优势。</p><h3 id="厨房里的酱油瓶"><a href="#厨房里的酱油瓶" class="headerlink" title="厨房里的酱油瓶"></a>厨房里的酱油瓶</h3><p>有一种酱油叫海天，有着一个无比蛋疼的封口设计。打开瓶盖，拉开拉环，倒出香醇的酱油后，你会发现，瓶盖合不上了！酱油这种长期使用产品，不清楚这种汽水拉环一样的一次性设计是为了什么。</p><p>而对比厨房里的另一瓶调料——白醋，就明显看出设计上的差距。白醋有一个方便拧开的大瓶盖，为了方便控制倒醋时的流速，还在内部加了一个控制流速的狭缝，可谓方便至极。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css&quot;&gt;&lt;p&gt;Meta: 本文章用来记录平时遇到的问题以及相应的解决方案&lt;/p&gt;
&lt;h2 </summary>
      
    
    
    
    <category term="作为工程师" scheme="https://xinghua.space/categories/%E4%BD%9C%E4%B8%BA%E5%B7%A5%E7%A8%8B%E5%B8%88/"/>
    
    
  </entry>
  
  <entry>
    <title>javascript 犀牛书（第六版）</title>
    <link href="https://xinghua.space/2016/01/19/learn-javascript-follow-definitive-guide/"/>
    <id>https://xinghua.space/2016/01/19/learn-javascript-follow-definitive-guide/</id>
    <published>2016-01-19T05:01:58.000Z</published>
    <updated>2024-03-02T07:11:51.839Z</updated>
    
    <content type="html"><![CDATA[<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css"><p>记录阅读《javascript 权威指南》中，个人认为比较核心或是比较容易混乱的地方。<br>同时会加入在阅读过程中参阅的一些优秀的扩展文章。</p><p><strong>更新记录</strong></p><blockquote><p>2016-01-18 更新到 try-except-finally 语句<br>2016-04-07 文章改名。将文章结构分为核心和模糊点</p></blockquote><p><strong>我认为书中的核心部分</strong></p><blockquote><ol><li>语言核心部分</li><li>变量类型</li><li>strict 模式</li><li>词法作用域、函数，闭包、this、call、apply、bind</li><li>原型系统</li></ol></blockquote><h2 id="核心部分"><a href="#核心部分" class="headerlink" title="核心部分"></a>核心部分</h2><h3 id="语言核心"><a href="#语言核心" class="headerlink" title="语言核心"></a>语言核心</h3><h4 id="变量及变量类型"><a href="#变量及变量类型" class="headerlink" title="变量及变量类型"></a>变量及变量类型</h4><p>javascript 中的变量本身没有类型，给一个变量赋值时，其实是这个变量引用了这个值。这根 python 中是一致的。 </p><p>他们都区别于 C 语言等固定类型的变量，在 C 语言中，当声明一个变量时，需要指定它的类型，这个变量其实就是一个固定大小的空间，直接用于存放变量的值。数组也是一样，一个数组只能存储同样类型的值，C 语言需要根据类型决定如何分配内存大小，比如 int 是 4 个字节。</p><p>而 javascript 和 Python 中，无需声明变量类型。变量只是对数据的引用，而类型是数据本身决定的，这个变量引用了什么类型，这个变量就是什么类型，javascript 中的数据类型分为两类（貌似是借鉴了 java）:</p><h4 id="原始类型"><a href="#原始类型" class="headerlink" title="原始类型"></a>原始类型</h4><ul><li>原始类型 primitive type（5 种）<ul><li>数字</li><li>字符串</li><li>布尔值</li><li>null</li><li>undefined</li></ul></li></ul><p><strong>注意：</strong>原始类型不是对象，但你可能会见过 APrimitiveType.method 的调用形式，这是因为数字，字符串，布尔值存在「包装对象」这个概念。</p><h4 id="对象类型"><a href="#对象类型" class="headerlink" title="对象类型"></a>对象类型</h4><ul><li>对象类型（object）（除了 5 种原始类型的数据类型，都是对象类型）<ul><li>普通对象（名值对对象）</li><li>数组</li><li>函数 - javascript 可以将 function 对象当做普通对象对待</li></ul></li></ul><h4 id="严格模式：use-strict"><a href="#严格模式：use-strict" class="headerlink" title="严格模式：use strict"></a>严格模式：use strict</h4><p>如果你了解一些 javascript 的历史，就会清楚 javascript 是 Brendan Eich 花了十天时间设计出来的，主要参考了 Scheme，Self，C，Java 等语言。虽然有现成的语言可以借鉴，但是在如此短的时间内，想要完成一个非常严格的设计是不太现实的。因此 Javascript 本身在设计之初就带有一些隐藏的缺陷。再加上浏览器大战时的迅速推广，这些缺陷没有足够的时间得到修正，便开始成为标准。所以使得这些缺陷一直保留了下来。</p><p>关于这些缺陷，可以简单参考阮一峰的文章：<a href="https://www.ruanyifeng.com/blog/2011/06/10_design_defects_in_javascript.html">javascript 的十个设计缺陷</a>，以及书籍：《javascript: the good parts》</p><p>use strict 其实是 ECMAscript 5 中加入的指令，非常接近于语句，但又有所区分：不包含关键字，只是个字符串字面量，而且只能出现在特定的位置。</p><p>use strict 的目的是使其后的代码使用 js 的「严格模式」执行，它是 js 的一个子集，修正了一些语言的重要缺陷，并提供健壮的查错功能和增强的安全机制。严格模式与非严格模式有一些重要的区别。</p><ul><li>严格模式中不能使用 with 语句</li><li>严格模式中变量都要先 var 声明（非严格模式不声明使用会给全局对象添加一个新属性）</li><li>严格模式中，函数调用时 this 值为 undefined，而不是全局对象。</li></ul><h2 id="模糊点"><a href="#模糊点" class="headerlink" title="模糊点"></a>模糊点</h2><h3 id="包装对象"><a href="#包装对象" class="headerlink" title="包装对象"></a>包装对象</h3><p>原始类型不是对象，但你可能会见过 APrimitiveType.method 的调用形式，这是因为数字，字符串，布尔值存在「包装对象」这个概念。也就是说，档使用上面的。运算时，javascript 会自动调用 new String(s) | new Number(s) | new Boolean(s) 的方式将这三种基本类型临时转换为对象，并继承相应类型的方法。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//一个经典的例子</span></span><br><span class="line"><span class="keyword">var</span> s = <span class="string">&quot;test&quot;</span>;</span><br><span class="line">s.<span class="property">len</span> = <span class="number">4</span>;  <span class="comment">//因为点运算，这里会临时建立一个 string 对象，但是随即又销毁了</span></span><br><span class="line"><span class="keyword">var</span> t = s.<span class="property">len</span>; <span class="comment">//这里也会创建一个 string 对象，但是已经不是上面那个了，故 undefined</span></span><br></pre></td></tr></table></figure><ul><li>null 和 undefined 没有包装对象</li><li>可以使用构造函数显式地构造包装对象。</li></ul><h3 id="变量声明提前和变量可配置性"><a href="#变量声明提前和变量可配置性" class="headerlink" title="变量声明提前和变量可配置性"></a>变量声明提前和变量可配置性</h3><ul><li>声明提前<ul><li>指的是 var 声明变量时，会提前到其所在作用域的顶部</li></ul></li><li>可配置性<ul><li>全局变量是全局对象的属性，但局部变量没有此规定</li><li>var 声明的全局变量是不可配置的，无法通过 delete 运算符删除</li></ul></li></ul><h3 id="eval-运算符"><a href="#eval-运算符" class="headerlink" title="eval 运算符"></a>eval 运算符</h3><p>eval() 实际上是个函数，但它早已被当成运算符看待。ECMAscript 会尽量约束 eval() 的表现，使其看起来像个表达式。</p><p>这是因为如果将 eval 当做普通的函数对待，不做任何限制的话，会有很多缺点。一是因为 eval() 会动态的执行代码段，破坏原来的代码结构，解释器难以优化。二是因为如果 eval 是普通的函数，那么它就可以被赋值给其他的变量名，比如 g &#x3D; eval, 这样导致任何使用 g 的地方，也会产生上述问题，导致 javascript 的代码优化变得困难，性能堪忧。</p><p>综上所述，如果 eval 的表现行为像一个运算符的话，就不会有上述这么严重的问题。所以在 ECMAscript 语法中不断的约束它，让其表现更接近为运算符。</p><h3 id="标签语句"><a href="#标签语句" class="headerlink" title="标签语句"></a>标签语句</h3><p>主要用于配合 continue 和 break 使用，来实现更灵活一些的跳转。</p><h3 id="throw-try-catch-finally-语句"><a href="#throw-try-catch-finally-语句" class="headerlink" title="throw&#x2F;try&#x2F;catch&#x2F;finally 语句"></a>throw&#x2F;try&#x2F;catch&#x2F;finally 语句</h3><p>之前写过一篇<a href="">那些年我在 python 中扑过的街</a>，在其中提到过 python 中，try&#x2F;except&#x2F;finally 中容易进的坑。</p><p>这个坑在 javascript 中也是同样的，就像那篇文章里说的那样，因为 finally 的设计目的就是无论如何都会执行，那么一旦 finally 中出现了跳转语句，其他语句中的返回内容就会被忽略。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">finallyTest</span>(<span class="params"></span>)&#123;</span><br><span class="line">    <span class="keyword">var</span> x = <span class="string">&#x27;catch&#x27;</span>, y = <span class="string">&#x27;except&#x27;</span>, z = <span class="string">&#x27;finally&#x27;</span>;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        k = x + y;</span><br><span class="line">        a = b;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;here is try------------&quot;</span>);</span><br><span class="line">    &#125; <span class="keyword">catch</span>(e) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;here is catch----------&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> x;</span><br><span class="line">    &#125; <span class="keyword">finally</span>&#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;here is finally---------&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> z;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//执行</span></span><br><span class="line"><span class="title function_">finallyTest</span>()</span><br><span class="line"><span class="comment">//返回值</span></span><br><span class="line">here is <span class="keyword">catch</span>----------</span><br><span class="line">here is <span class="keyword">finally</span>---------</span><br><span class="line"><span class="string">&#x27;finally&#x27;</span></span><br></pre></td></tr></table></figure><h3 id="函数名"><a href="#函数名" class="headerlink" title="函数名"></a>函数名</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 直接声明函数是具有函数名的</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">foo</span>(<span class="params"></span>)&#123;&#125;</span><br><span class="line">foo.<span class="property">name</span>  <span class="comment">// 函数名为 foo</span></span><br><span class="line"><span class="keyword">var</span> bar = foo</span><br><span class="line">bar.<span class="property">name</span>  <span class="comment">// 将函数赋值给一个变量，只是让变量指向了函数结构，并不会改变函数结构本身</span></span><br><span class="line"><span class="comment">// 函数表达式生成的是匿名函数</span></span><br><span class="line"><span class="keyword">var</span> foo = <span class="keyword">function</span>(<span class="params"></span>)&#123;&#125;</span><br><span class="line">foo.<span class="property">name</span> <span class="comment">// &quot;&quot; (空字符串)</span></span><br><span class="line"><span class="comment">// 函数名称只存在于函数自身结构内，被传递时不会改变这个结构</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">foo</span>(<span class="params"></span>)&#123;&#125;</span><br><span class="line"><span class="keyword">var</span> o =&#123;</span><br><span class="line">    <span class="attr">a</span>: <span class="string">&#x27;a&#x27;</span>,</span><br><span class="line">    <span class="attr">bar</span>: foo</span><br><span class="line">&#125;;</span><br><span class="line">o.<span class="property">bar</span>.<span class="property">name</span> <span class="comment">// foo</span></span><br></pre></td></tr></table></figure><h3 id="this-引用丢失"><a href="#this-引用丢失" class="headerlink" title="this 引用丢失"></a>this 引用丢失</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 函数被多次传递时可能发生</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">foo</span>(<span class="params"></span>)&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">a</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> obj = &#123;</span><br><span class="line">    <span class="attr">a</span>: <span class="number">2</span>,</span><br><span class="line">    <span class="attr">foo</span>: foo</span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">var</span> bar = obj.<span class="property">foo</span>;</span><br><span class="line"><span class="keyword">var</span> a=<span class="string">&quot;oops, global&quot;</span>;</span><br><span class="line"><span class="title function_">bar</span>(); <span class="comment">//&quot;oops, global&quot;</span></span><br><span class="line"><span class="comment">// 回调函数中可能发生（异步）</span></span><br><span class="line"><span class="comment">// 代码同上</span></span><br><span class="line"><span class="built_in">setTimeout</span>(obj.<span class="property">foo</span>, <span class="number">100</span>); <span class="comment">// &quot;oops, global&quot;</span></span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;https://cdn.jsdelivr.net/hint.css/2.4.1/hint.min.css&quot;&gt;&lt;p&gt;记录阅读《javascript 权威指南》中，个人认为比较核心或是比较容易混</summary>
      
    
    
    
    <category term="作为工程师" scheme="https://xinghua.space/categories/%E4%BD%9C%E4%B8%BA%E5%B7%A5%E7%A8%8B%E5%B8%88/"/>
    
    
  </entry>
  
</feed>
