<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Saito</title>
    <link>https://ruby-china.org/Saito</link>
    <description>#programmer</description>
    <language>en-us</language>
    <item>
      <title>前端架构分享</title>
      <description>&lt;h2 id="前端架构"&gt;前端架构&lt;/h2&gt;&lt;h2 id="总述"&gt;总述&lt;/h2&gt;
&lt;p&gt;在互联网应用越来越大，越来越复杂的今天，我们不可避免的需要工具来管理我们的前端代码。
替代以前的一个巨大的脚本文件，我们希望可以将文件写入不同的文件模块。并且希望代码可以
重用，可以简单的引用和添加各种各样的依赖到我们的项目（无论是菜单一样的 UI 组件还是
一个类似 jQuery 的 DOM 操作库）。不止是 JavaScript 我们希望可以用这种方式来组织，
他应该也包含 CSS，HTML 模板，字体，图片和其他静态文件。&lt;/p&gt;
&lt;h4 id="为什么前端需要模块化开发"&gt;为什么前端需要模块化开发&lt;/h4&gt;
&lt;p&gt;随着互联网应用越来越大，前端的开发也越来越复杂。如果还维持在以往以页面为单位的开发，
会导致很多问题，类似依赖管理，命名冲突等棘手的问题。&lt;/p&gt;

&lt;p&gt;命名冲突是最常见的问题：&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// util.js&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// logger.js&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当页面的 &lt;code&gt;script&lt;/code&gt; 标签同时依赖这两个文件时便会产生冲突，导致后面函数会覆盖前面的。
从而可能会产生一些预想之外的结果。&lt;/p&gt;

&lt;p&gt;而传统的解决方案是使用命名空间：&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// util.js&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;util&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// logger.js&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样会带来显而易见的问题，所有的代码会变得冗余且编写困难。&lt;/p&gt;

&lt;p&gt;如果使用模块化的编写方案，例如 Common Module Definition，代码见的依赖会变得格外简单。&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// util.js&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;log&lt;/span&gt;

&lt;span class="c1"&gt;// logger.js&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;log&lt;/span&gt;

&lt;span class="c1"&gt;// app.js using util.js log for logging&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;util.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello Module Definition&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;util.js&lt;/code&gt; 与 &lt;code&gt;logger.js&lt;/code&gt; 不会相互冲突，他们会被工具包装为 CMD 下的定义方式。
然后通过依赖的方式来解决冲突&lt;/p&gt;

&lt;p&gt;依赖管理同样是一个棘手的问题：&lt;/p&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/util.js"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/javascript"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/logger.js"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/javascript"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/app.js"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/javascript"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你有一大堆的依赖关系，你必须依序将所有的文件引入，否则会导致变量未定义等问题。
如果使用了 Common Module Definition 便可以无序的引入组件文件。&lt;/p&gt;

&lt;p&gt;在样式方面由于 CSS 与浏览器本身的限制我们仍然无法使用这样的技术来划分模块。&lt;/p&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* layout.css */&lt;/span&gt;
&lt;span class="nc"&gt;.box&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* dropdown.css */&lt;/span&gt;
&lt;span class="nc"&gt;.box&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样的话 dropdown.css 的 .box 便会覆盖之前的 .box 的样式，所以我们需要在模块中添加限制。&lt;/p&gt;

&lt;p&gt;所以在样式表方面我们需要详细的划分模块的命名空间，例如在 dropbox.css 中我们可以用这样的命名方式 .dropdown .box 的方式。
这边便不会影响到父级的样式。&lt;/p&gt;
&lt;h4 id="如何进行模块化开发"&gt;如何进行模块化开发&lt;/h4&gt;
&lt;p&gt;首先对页面进行模块化的拆分，将模块的定义文件放在一个文件夹下，其中包含有
JavaScript CSS 以及 Templates（前后端）的文件。模块的脚本文件默认会被 CMD 包装，
而 CSS 文件，开发着需要对文件进行特殊的命名，默认以模块文件夹名为命名空间，
以防与别人冲突，而模板文件则不会有这样的顾虑。&lt;/p&gt;

&lt;p&gt;我们开发了 Linner 来支持模块化的开发。&lt;/p&gt;
&lt;h2 id="架构概览"&gt;架构概览&lt;/h2&gt;
&lt;p&gt;&lt;img src="http://cl.ly/image/1Y1U0v0m2c1C/Image%202014-04-07%20at%209.36.05%20PM.png" title="" alt=""&gt;&lt;/p&gt;

&lt;p&gt;在前端项目中，我们在底层拥有基础组件库与可视化编辑框架用于装修需求。
在基础组件之上，我们会沉淀出标准的组件库，类似电商标准组件库之类的类库，
而真正的类库中开发者也需要将自己的组织为组件的形式。&lt;/p&gt;

&lt;p&gt;而工具则为整个过程保驾护航。&lt;/p&gt;
&lt;h2 id="工具阐述"&gt;工具阐述&lt;/h2&gt;
&lt;p&gt;简单来说，Linner 允许我们做：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;项目结构化&lt;/li&gt;
&lt;li&gt;页面组件化&lt;/li&gt;
&lt;li&gt;仓库管理&lt;/li&gt;
&lt;li&gt;使用 CoffeeScript 与 SCSS 来替代 JavaScript 与 CSS&lt;/li&gt;
&lt;li&gt;合并 CSS 与 JavaScript 文件&lt;/li&gt;
&lt;li&gt;复制 CSS 与 JavaScript 文件&lt;/li&gt;
&lt;li&gt;预编译 CSS 与 JavaScript 文件&lt;/li&gt;
&lt;li&gt;合并图片至一张大图（Sprites）&lt;/li&gt;
&lt;li&gt;压缩 CSS 与 JavaScript 文件&lt;/li&gt;
&lt;li&gt;监视文件系统变化并实时更新&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="1. 项目结构化"&gt;1. 项目结构化&lt;/h4&gt;
&lt;p&gt;项目通过标准化的方式来组织：&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
├── app
│&amp;nbsp;&amp;nbsp; ├── components
│&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp; └── dropdown
│&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp;     ├── view.coffee
│&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp;     ├── view.hbs
│&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp;     └── view.scss
│&amp;nbsp;&amp;nbsp; ├── images
│&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp; └── logo.png
│&amp;nbsp;&amp;nbsp; ├── scripts
│&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp; └── app.coffee
│&amp;nbsp;&amp;nbsp; ├── styles
│&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp; └── app.scss
│&amp;nbsp;&amp;nbsp; ├── templates
│&amp;nbsp;&amp;nbsp; │&amp;nbsp;&amp;nbsp; └── welcome.hbs
│&amp;nbsp;&amp;nbsp; └── views
│&amp;nbsp;&amp;nbsp;     └── index.html
├── bin
│&amp;nbsp;&amp;nbsp; └── server
├── config.yml
├── public
├── &lt;span class="nb"&gt;test&lt;/span&gt;
└── vendor
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;app&lt;/code&gt; 文件夹是用户自己编写代码的地方&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;images&lt;/code&gt; 用以存放项目相关的图片文件&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;scripts&lt;/code&gt; 用以存放项目相关的 JavaScript 文件&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;styles&lt;/code&gt; 用以存放项目相关的 Stylesheet 文件&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;templates&lt;/code&gt; 用以存放项目相关的前端模板文件&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;views&lt;/code&gt; 用以存放项目相关的后端模板文件&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;components&lt;/code&gt; 用以存放项目的组件文件&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;config.yml&lt;/code&gt; 是整个项目的配置文件&lt;/p&gt;

&lt;p&gt;&lt;code&gt;bin&lt;/code&gt; 文件夹可以让用户很方便的启动一个本地的服务器，以当前文件夹作为根&lt;/p&gt;

&lt;p&gt;&lt;code&gt;test&lt;/code&gt; 文件夹可以使用户编写一些单元测试来测试自己的前端项目&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vendor&lt;/code&gt; 文件夹可以使用户引入第三方的代码组件，如 jQuery、Underscore 等&lt;/p&gt;

&lt;p&gt;&lt;code&gt;public&lt;/code&gt; 文件夹是项目打包后文件位置，发布项目所需要的所有文件&lt;/p&gt;
&lt;h4 id="2. 页面组件化"&gt;2. 页面组件化&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;不要面向页面编程，要面向组件编程。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;当拿到网站的整体设计稿时，我们应该首先去找出页面间有相同逻辑的模块。
将他们抽出，考虑如何将其设计为可复用的模块。&lt;/p&gt;

&lt;p&gt;我们可以将模块的内容包含 JavaScript CSS 与前后端模板组织在 &lt;code&gt;app/components&lt;/code&gt;
内，通过在 &lt;code&gt;app/scripts&lt;/code&gt; 里面的 &lt;code&gt;app.coffee&lt;/code&gt; 中去初始化所有的组件。&lt;/p&gt;

&lt;p&gt;通过 &lt;code&gt;cmd&lt;/code&gt; 的形式去管理组件与组件之间的依赖关系。这样组件内部就可以通过
&lt;code&gt;module.exports = "dropdown"&lt;/code&gt; 与 &lt;code&gt;require "dropdown"&lt;/code&gt; 这样的形式去导出与依赖组件。&lt;/p&gt;
&lt;h4 id="3. 仓库管理"&gt;3. 仓库管理&lt;/h4&gt;
&lt;p&gt;通过 &lt;code&gt;bundles&lt;/code&gt; 来管理远端依赖，在项目中可以非常方便的引入一些著名的第三方库。
如 jQuery，Underscore 等。&lt;/p&gt;

&lt;p&gt;依赖可以规定多个版本，当需要升级版本时，可以更改 &lt;code&gt;version&lt;/code&gt; 与 &lt;code&gt;url&lt;/code&gt;
在工具下次启动时便可以拉取新版本的依赖。如果希望依赖一直为最新状态，可以将 &lt;code&gt;version&lt;/code&gt; 设置为 &lt;code&gt;master&lt;/code&gt; 这样工具会在每次启动时都获取最新的文件。&lt;/p&gt;
&lt;h4 id="4. 使用 CoffeeScript 与 SCSS 来替代 JavaScript 与 CSS"&gt;4. 使用 CoffeeScript 与 SCSS 来替代 JavaScript 与 CSS&lt;/h4&gt;&lt;h5 id="CoffeeScript"&gt;CoffeeScript&lt;/h5&gt;
&lt;p&gt;CoffeeScript 是这一门编程语言构建在 JavaScript 之上，其被编译成高效的 JavaScript，
这样你就可以在 Web 浏览器上运行它，或是通过诸如用于服务器端应用的 Node.js 一类的技术来使用它。
编译过程通常都很简单，产生出来的 JavaScript 与许多的最佳做法都保持了一致。&lt;/p&gt;
&lt;h5 id="SCSS"&gt;SCSS&lt;/h5&gt;
&lt;p&gt;SCSS 扩展了 CSS3，增加了规则、变量、混入、选择器、继承等等特性。
SCSS 生成良好格式化的 CSS 代码，易于组织和维护。&lt;/p&gt;
&lt;h5 id="使用成本"&gt;使用成本&lt;/h5&gt;
&lt;p&gt;使用 CoffeeScript 与 SCSS 可以大幅降低开发成本，使用 CoffeeScript 可以避免一些常见的 JavaScript 开发错误。
而 SCSS 则可以更好的抽象样式文件，使样式得到更好的维护。并且 CoffeeScript 与 SCSS 的学习成本都很低，
前端可以通过很简短的学习就能立刻写出优雅的代码。&lt;/p&gt;
&lt;h4 id="5. 合并 CSS 与 JavaScript 文件"&gt;5. 合并 CSS 与 JavaScript 文件&lt;/h4&gt;
&lt;p&gt;前端文件的合并可以明显的减少 HTTP 请求，明显的加快网页的浏览速度。&lt;/p&gt;
&lt;h4 id="6. 复制 CSS 与 JavaScript 文件"&gt;6. 复制 CSS 与 JavaScript 文件&lt;/h4&gt;
&lt;p&gt;复制文件是一个很普遍的需求，可以将文件从一个位置复制到另一个位置。如果是 CoffeeScript 文件或者 SCSS 文件，工具会帮助转换为对应的 Javascript 与 CSS 文件。&lt;/p&gt;
&lt;h4 id="7. 预编译 JavaScript 模板文件"&gt;7. 预编译 JavaScript 模板文件&lt;/h4&gt;
&lt;p&gt;随着互联网应用越来越大，前端模板的需求也日渐突出。在使用前端模板的过程中，
为了提高前端的渲染性能，我们需要对前端模板进行预编译。预编译的结果是使 &lt;code&gt;templates&lt;/code&gt;
文件能直接转化为 JavaScript 的方法调用。这样可以以非常快的速度来渲染前端模板。&lt;/p&gt;
&lt;h4 id="8. 合并图片至一张大图（Sprites）"&gt;8. 合并图片至一张大图（Sprites）&lt;/h4&gt;
&lt;p&gt;当页面内的图片很多时，会产生多个 HTTP 请求，当请求变多时会严重影响网站的速度。
所以我们需要将多个 PNG 图片合并成一张图片。同时利用 CSS 的 &lt;code&gt;background&lt;/code&gt;
来显示对应的单个图片&lt;/p&gt;
&lt;h4 id="9. 压缩 CSS 与 JavaScript 文件"&gt;9. 压缩 CSS 与 JavaScript 文件&lt;/h4&gt;
&lt;p&gt;在项目发布上线时需要将资源文件进行最大程度的压缩。从而减少 HTTP 请求文件的体积。
从而可以将文件尽快的传输给用户，使页面更快的展示出来。&lt;/p&gt;

&lt;p&gt;工具提供了快速的文件名的版本替换，可以使服务器更好的缓存压缩后的文件。&lt;/p&gt;
&lt;h4 id="10. 监视文件系统变化并实时更新"&gt;10. 监视文件系统变化并实时更新&lt;/h4&gt;
&lt;p&gt;文件系统的实时监控可以监控到项目内文件的变动，同时重新执行整个工具的逻辑。&lt;/p&gt;

&lt;p&gt;在开发阶段，我们可以尽最大程度的提高开发者的效率。例如使用浏览器实时刷新。
当文件系统有任何变化时，工具会发动 LiveReload 来自动刷新页面，
当用户只修改了 CSS 文件时，我们甚至可以不刷新页面，直接重载 CSS 文件。
极大的提高开发效率。&lt;/p&gt;
&lt;h2 id="性能调优"&gt;性能调优&lt;/h2&gt;
&lt;p&gt;大约 80%-90% 的终端响应时间是花费在前端，其中包含下载页面中的图片，样式表，脚本，flash 等。Yahoo 为此总结了 14 条规则，成为网站性能优化的事实标准。&lt;/p&gt;
&lt;h4 id="雅虎网站性能优化的 14 条规则："&gt;雅虎网站性能优化的 14 条规则：&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;尽可能减少 HTTP 请求数&lt;/li&gt;
&lt;li&gt;使用 CDN（内容分发网络）&lt;/li&gt;
&lt;li&gt;为文件头指定 Expires 或 Cache-Control，使内容具有缓存性&lt;/li&gt;
&lt;li&gt;使用 Gzip 压缩内容&lt;/li&gt;
&lt;li&gt;把 CSS 放到顶部&lt;/li&gt;
&lt;li&gt;把 JavaScript 放在底部&lt;/li&gt;
&lt;li&gt;避免在 CSS 中使用 Expressions&lt;/li&gt;
&lt;li&gt;把 JavaScript 和 CSS 都放到外部文件中&lt;/li&gt;
&lt;li&gt;减少 DNS 查找次数&lt;/li&gt;
&lt;li&gt;压缩 JavaScript 和 CSS&lt;/li&gt;
&lt;li&gt;避免重定向&lt;/li&gt;
&lt;li&gt;剔除重复的 JavaScript 和 CSS&lt;/li&gt;
&lt;li&gt;配置 Etags&lt;/li&gt;
&lt;li&gt;使 AJAX 缓存&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="对规则的分析："&gt;对规则的分析：&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;代码编写方面的规则：

&lt;ul&gt;
&lt;li&gt;把 CSS 放到顶部&lt;/li&gt;
&lt;li&gt;把 JavaScript 放在底部&lt;/li&gt;
&lt;li&gt;把 JavaScript 和 CSS 都放到外部文件中&lt;/li&gt;
&lt;li&gt;避免在 CSS 中使用 Expressions&lt;/li&gt;
&lt;li&gt;使 AJAX 缓存&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;打包方面的规则：

&lt;ul&gt;
&lt;li&gt;尽可能减少 HTTP 请求数&lt;/li&gt;
&lt;li&gt;压缩 JavaScript 和 CSS&lt;/li&gt;
&lt;li&gt;剔除重复的 JavaScript 和 CSS&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;部署方面的规则：

&lt;ul&gt;
&lt;li&gt;使用 CDN（内容分发网络）&lt;/li&gt;
&lt;li&gt;为文件头指定 Expires 或 Cache-Control，使内容具有缓存性&lt;/li&gt;
&lt;li&gt;使用 Gzip 压缩内容&lt;/li&gt;
&lt;li&gt;减少 DNS 查找次数&lt;/li&gt;
&lt;li&gt;避免重定向&lt;/li&gt;
&lt;li&gt;配置 Etags&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="对规则的实践"&gt;对规则的实践&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;部署方面的规则，应用 Nginx 为静态文件添加 Expires 跟 Cache-Control 头，
配置 Etags，并启用 Gzip 压缩。并且避免在 Nginx 中做重定向，有条件的话可以
启用 CDN，并优化网络配置以减少 DNS 查找次数。&lt;/li&gt;
&lt;li&gt;代码编写方面的规则，需要在编写代码种形成规范。默认使用类似 jQuery 这样的库
便可以对 AJAX 进行缓存。&lt;/li&gt;
&lt;li&gt;打包方面 Linner 可以合并 JavaScript 与 CSS 文件，并且支持小图片的合并，
用以减少 HTTP 请求数。同时 Linner 的仓库管理可以避免重复的 JavaScript 与 CSS
文件的出现。在 &lt;code&gt;build&lt;/code&gt; 过后所有的文件将会被压缩。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="附件"&gt;附件&lt;/h2&gt;&lt;h4 id="工具的使用"&gt;工具的使用&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;安装 Ruby 2.0.0 以上版本&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;安装 Linner 及其使用规则&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 安装 Linner&lt;/span&gt;
gem &lt;span class="nb"&gt;install &lt;/span&gt;linner

&lt;span class="c"&gt;# 使用 Linner 创建项目结构&lt;/span&gt;
linner new webapp &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;webapp

&lt;span class="c"&gt;# 在项目下启动 Linner&lt;/span&gt;
linner watch

&lt;span class="c"&gt;# 退出 Linner&lt;/span&gt;
CTRL + C

&lt;span class="c"&gt;# 打包资源文件&lt;/span&gt;
linner build

&lt;span class="c"&gt;# 清空打包的资源文件&lt;/span&gt;
linner clean
&lt;/code&gt;&lt;/pre&gt;&lt;h4 id="config.yml 文件配置详解"&gt;config.yml 文件配置详解&lt;/h4&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app"&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test"&lt;/span&gt;
  &lt;span class="na"&gt;public&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;public"&lt;/span&gt;
&lt;span class="na"&gt;groups&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scripts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;app/scripts&lt;/span&gt;
    &lt;span class="na"&gt;concat&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/scripts/app.js"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/**/*.{js,coffee}"&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/scripts/vendor.js"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vendor/**/*.{js,coffee}"&lt;/span&gt;
    &lt;span class="na"&gt;order&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;vendor/jquery-1.10.2.js&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;...&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;app/scripts/app.coffee&lt;/span&gt;
  &lt;span class="na"&gt;styles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;app/styles&lt;/span&gt;
    &lt;span class="na"&gt;concat&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/styles/app.css"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/styles/**/[a-z]*.{css,scss,sass}"&lt;/span&gt;
  &lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;app/images&lt;/span&gt;
    &lt;span class="na"&gt;sprite&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;../app/images/icons.scss"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/images/**/*.png"&lt;/span&gt;
  &lt;span class="na"&gt;views&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;app/views&lt;/span&gt;
    &lt;span class="na"&gt;copy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/views/**/*.html"&lt;/span&gt;
  &lt;span class="na"&gt;templates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;app/templates&lt;/span&gt;
    &lt;span class="na"&gt;precompile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/scripts/templates.js"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/templates/**/*.hbs"&lt;/span&gt;
&lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;wrapper&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cmd&lt;/span&gt;
  &lt;span class="na"&gt;ignored&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vendor/**/*&lt;/span&gt;
  &lt;span class="na"&gt;definition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/scripts/app.js&lt;/span&gt;
&lt;span class="na"&gt;sprites&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/images/&lt;/span&gt;
  &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/images/&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.icon-&lt;/span&gt;
&lt;span class="na"&gt;revision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;index.html&lt;/span&gt;
&lt;span class="na"&gt;notification&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;bundles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;jquery.js&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1.10.2&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://code.jquery.com/jquery-1.10.2.js&lt;/span&gt;
  &lt;span class="na"&gt;handlebars.js&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1.0.0&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://raw.github.com/wycats/handlebars.js/1.0.0/dist/handlebars.runtime.js&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;paths&lt;/code&gt; 表示当前工具做监视的文件系统目录&lt;/p&gt;

&lt;p&gt;&lt;code&gt;groups&lt;/code&gt; 区分了不同的组，每个组可以有一个名字。在组内部的声明中需要指定当前组的
&lt;code&gt;paths&lt;/code&gt;，然后可以指定一系列的操作原语，包括：&lt;code&gt;concat&lt;/code&gt; &lt;code&gt;order&lt;/code&gt; &lt;code&gt;copy&lt;/code&gt;
&lt;code&gt;precompile&lt;/code&gt; &lt;code&gt;sprite&lt;/code&gt; 等&lt;/p&gt;

&lt;p&gt;&lt;code&gt;modules&lt;/code&gt; 定义了需要被 &lt;code&gt;CMD&lt;/code&gt; 包装的文件路径，以及包装定义的头文件连接位置&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sprites&lt;/code&gt; 定义了图片 &lt;code&gt;sprites&lt;/code&gt; 的一些生成规则，例如以 &lt;code&gt;.icon-&lt;/code&gt; 开头来生成 CSS
列表，这样用户便可以以这样的 CSS 选择器来直接生成样式。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;revision&lt;/code&gt; 定义了需要被加载 &lt;code&gt;rev&lt;/code&gt; 的文件，用以 md5 的文件名来替换旧文件名&lt;/p&gt;

&lt;p&gt;&lt;code&gt;notification&lt;/code&gt; 定义了是否需要有通知系统，（用以 Mac 系统的通知）&lt;/p&gt;

&lt;p&gt;&lt;code&gt;bundles&lt;/code&gt; 定义了项目的依赖关系，项目可以依赖很多第三方的项目，可以自定义版本号。
如果需要每次启动都更新最新版本的依赖，可以将 &lt;code&gt;version&lt;/code&gt; 设置为 &lt;code&gt;master&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Linner: &lt;a href="https://github.com/SaitoWu/linner" rel="nofollow" target="_blank"&gt;https://github.com/SaitoWu/linner&lt;/a&gt;
原文：&lt;a href="http://saito.im/note/The-Architecture-of-F2E/" rel="nofollow" target="_blank"&gt;http://saito.im/note/The-Architecture-of-F2E/&lt;/a&gt;&lt;/p&gt;</description>
      <author>Saito</author>
      <pubDate>Fri, 29 May 2015 11:34:27 +0800</pubDate>
      <link>https://ruby-china.org/topics/25802</link>
      <guid>https://ruby-china.org/topics/25802</guid>
    </item>
    <item>
      <title>Simba v0.8.0 has been released!</title>
      <description>&lt;p&gt;&lt;a href="https://github.com/SaitoWu/simba" rel="nofollow" target="_blank" title=""&gt;Simba&lt;/a&gt; 致力于做 Ruby off Rails 的最佳实践。&lt;/p&gt;

&lt;p&gt;Changelog:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;去掉了 Sprockets 作为依赖。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;引入 &lt;a href="https://github.com/SaitoWu/linner" rel="nofollow" target="_blank" title=""&gt;Linner&lt;/a&gt; 作为前端的管理工具。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;使用 ActiveRecord 作为数据库访问工具。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Usage:&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;simba new appname &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;appname
bundle &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# development&lt;/span&gt;
bundle &lt;span class="nb"&gt;exec &lt;/span&gt;rackup

&lt;span class="c"&gt;# production&lt;/span&gt;
rake asset:precompile
bundle &lt;span class="nb"&gt;exec &lt;/span&gt;rackup &lt;span class="nt"&gt;-E&lt;/span&gt; production
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;清明节终于有时间做了一下更新，有需求的可以试试。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/SaitoWu/simba" rel="nofollow" target="_blank"&gt;https://github.com/SaitoWu/simba&lt;/a&gt;&lt;/p&gt;</description>
      <author>Saito</author>
      <pubDate>Mon, 07 Apr 2014 19:16:38 +0800</pubDate>
      <link>https://ruby-china.org/topics/18453</link>
      <guid>https://ruby-china.org/topics/18453</guid>
    </item>
    <item>
      <title>[杭州] 端点网络科技有限公司 [Java / JavaScript]</title>
      <description>&lt;h2 id="关于我们"&gt;关于我们&lt;/h2&gt;&lt;h3 id="我们是谁"&gt;我们是谁&lt;/h3&gt;
&lt;p&gt;杭州端点网络科技有限公司。6 位前阿里系员工组成的完整团队，从视觉设计到 PD 以及前/后端开发，团队氛围没羞没臊。公司成立一年半，成功度过前期的危险期并且保持不错的盈利。&lt;/p&gt;
&lt;h3 id="我们做什么"&gt;我们做什么&lt;/h3&gt;
&lt;p&gt;电商解决方案养活自己（咨询和外包）、O2O 平台争取发财。&lt;/p&gt;
&lt;h3 id="我们给什么"&gt;我们给什么&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;从有潜力的应届生到有工作经验的各种小伙伴们我们愿意给出 5-20K 的月薪收买（以及和团队发展挂钩的年终奖）&lt;/li&gt;
&lt;li&gt;另外还有可能会很值钱的期权（我们都希望它真的会很值钱，但说肯定会很值钱就是吹牛逼了）&lt;/li&gt;
&lt;li&gt;当然也有五险一金&lt;/li&gt;
&lt;li&gt;包午饭……&lt;/li&gt;
&lt;/ul&gt;

&lt;hr&gt;
&lt;h2 id="招聘职位"&gt;招聘职位&lt;/h2&gt;&lt;h3 id="Java工程师"&gt;Java 工程师&lt;/h3&gt;&lt;h4 id="技能要求"&gt;技能要求&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Java 基础扎实，了解 Util、Collection、Concurrent 包中的 API&lt;/li&gt;
&lt;li&gt;对至少一种 Java web 框架、IOC 框架熟练使用，并了解其优缺点&lt;/li&gt;
&lt;li&gt;熟悉 sql， *nix 操作系统&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="比基本要求更重要的"&gt;比基本要求更重要的&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;具备发现问题根源和解决问题的思路，懂得去哪里找到需要的信息和帮助&lt;/li&gt;
&lt;li&gt;热爱发现和使用新技术，热爱自己创造的东西&lt;/li&gt;
&lt;li&gt;良好的沟通能力，乐观开朗的性格&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="这是附加题"&gt;这是附加题&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;熟悉其他任意一种语言&lt;/li&gt;
&lt;li&gt;熟悉前端技术&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="前端工程师"&gt;前端工程师&lt;/h3&gt;&lt;h4 id="技能要求"&gt;技能要求&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;能熟练使用 JavaScript、CSS 和 HTML 构建设计师给出的页面&lt;/li&gt;
&lt;li&gt;了解 jQuery、underscore 等主流前端库、了解一种前端模板引擎例如 handlebars&lt;/li&gt;
&lt;li&gt;了解浏览器之间的差异，知道如何让你创造的东西在每一个浏览器上都有较一致的表现&lt;/li&gt;
&lt;li&gt;了解 CSS 3 和 HTML 5&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="比基本要求更重要的"&gt;比基本要求更重要的&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;具备发现问题根源和解决问题的思路，懂得去哪里找到需要的信息和帮助&lt;/li&gt;
&lt;li&gt;热爱发现和使用新技术，热爱自己创造的东西&lt;/li&gt;
&lt;li&gt;良好的沟通能力，乐观开朗的性格&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="这是附加题"&gt;这是附加题&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;知道并参与 &lt;code&gt;github.com&lt;/code&gt; 和 &lt;code&gt;stackoverflow.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;熟悉 CoffeeScript、Less、SASS 等提高生产力的工具&lt;/li&gt;
&lt;li&gt;熟悉 Java 或 Ruby&lt;/li&gt;
&lt;/ul&gt;

&lt;hr&gt;
&lt;h2 id="联系方式"&gt;联系方式&lt;/h2&gt;
&lt;p&gt;email: &lt;code&gt;anson0370@gmail.com&lt;/code&gt;&lt;/p&gt;
&lt;h2 id="工作地点"&gt;工作地点&lt;/h2&gt;
&lt;p&gt;杭州市 滨江区 六和路 368 号海外高层次人才创新创业基地&lt;/p&gt;</description>
      <author>Saito</author>
      <pubDate>Tue, 11 Feb 2014 13:22:24 +0800</pubDate>
      <link>https://ruby-china.org/topics/17165</link>
      <guid>https://ruby-china.org/topics/17165</guid>
    </item>
    <item>
      <title>I'm curious what guarantees you're looking for that you don't get with Go that you'd get in other languages.</title>
      <description>&lt;p&gt;&lt;a href="https://news.ycombinator.com/item?id=6469142" rel="nofollow" target="_blank"&gt;https://news.ycombinator.com/item?id=6469142&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;tl;dr 懒人包：RubyConfChina 讲师 Steve Klabnik 推荐你学 Rust &amp;amp; Haskell...&lt;/p&gt;</description>
      <author>Saito</author>
      <pubDate>Tue, 01 Oct 2013 01:18:05 +0800</pubDate>
      <link>https://ruby-china.org/topics/14495</link>
      <guid>https://ruby-china.org/topics/14495</guid>
    </item>
    <item>
      <title>录了一段 Screencast, 体会到 Ryan 的艰辛.</title>
      <description>&lt;p&gt;&lt;a href="https://vimeo.com/71944672" rel="nofollow" target="_blank" title=""&gt;&lt;img src="http://d.pr/i/MIyk+" title="" alt="Screencast"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;录 Screencast 真心难！&lt;/p&gt;

&lt;p&gt;单纯的不卡壳，顺利的演示下来就已经要受内伤了。更别提说话了.. &lt;/p&gt;

&lt;p&gt;这条 3 分钟的录了一个多小时，还没说话。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/SaitoWu/linner#screencast" rel="nofollow" target="_blank"&gt;https://github.com/SaitoWu/linner#screencast&lt;/a&gt;&lt;/p&gt;</description>
      <author>Saito</author>
      <pubDate>Thu, 08 Aug 2013 14:05:40 +0800</pubDate>
      <link>https://ruby-china.org/topics/13158</link>
      <guid>https://ruby-china.org/topics/13158</guid>
    </item>
    <item>
      <title>劝君远离 Windows, 西出窗户有情人.</title>
      <description>&lt;p&gt;&lt;a href="https://github.com/guard/listen" rel="nofollow" target="_blank" title=""&gt;Listen&lt;/a&gt; 监听文件夹变化。需要使用 wdm. 而 wdm 在 Listen 里面的实现是很挫的。监听到文件变化之后，还要再次递归文件夹。&lt;/p&gt;

&lt;p&gt;Less 依赖 V8, 在 Windows 上无法编译通过。&lt;/p&gt;

&lt;p&gt;popen3 在 Windows 上需要 win32-open3-19 这个 gem.&lt;/p&gt;

&lt;p&gt;popen4 在 windows 上更悲剧。&lt;/p&gt;

&lt;p&gt;EventMachine 在 Windows 环境下编译不过，换用 Reel 之后发现它依赖的 libev 版本比较老，还是编译不过。忍痛删除了 LiveReload 功能。&lt;/p&gt;

&lt;p&gt;Windows 版由于各方面的原因，速度非常慢..&lt;/p&gt;</description>
      <author>Saito</author>
      <pubDate>Mon, 29 Jul 2013 18:21:12 +0800</pubDate>
      <link>https://ruby-china.org/topics/12878</link>
      <guid>https://ruby-china.org/topics/12878</guid>
    </item>
    <item>
      <title>Linner, 一个 HTML5 应用打包器.</title>
      <description>&lt;h3 id="地址:"&gt;地址：&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://github.com/SaitoWu/linner" rel="nofollow" target="_blank"&gt;https://github.com/SaitoWu/linner&lt;/a&gt; &lt;/p&gt;
&lt;h3 id="特性:"&gt;特性：&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;快！&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;默认支持 &lt;code&gt;Sass&lt;/code&gt; 与 &lt;code&gt;Coffee&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;支持 OS X Lion 以上的 Notification. ( 在编译出错的时候弹出。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Linner 放弃了 Sprockets 的 directive processor, 用简单的 YAML 配置文件解决 &lt;code&gt;concat&lt;/code&gt; 问题。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Linner 同时解决了 Javascript 的模块化问题，所有 &lt;code&gt;app/&lt;/code&gt; 目录下的文件都会被 &lt;code&gt;CMD&lt;/code&gt; 包装，这样每个文件只需要 &lt;code&gt;module.exports&lt;/code&gt; 就可以导出可以被别的文件引用的内容。得到类似 node 的开发体验。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;实时 &lt;code&gt;concat&lt;/code&gt;, 支持 &lt;code&gt;watch&lt;/code&gt;, &lt;code&gt;$ linner watch&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Concat 后同时支持 &lt;code&gt;js, css&lt;/code&gt; 的 &lt;code&gt;compress&lt;/code&gt;. &lt;code&gt;$ linner build&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copy: 同时支持 &lt;code&gt;copy&lt;/code&gt; 操作，支持通配符 &lt;code&gt;copy&lt;/code&gt; 至 &lt;code&gt;dist&lt;/code&gt; 目录&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;关于为什么要开发 Linner 的缘由：&lt;a href="http://saito.im/note/Turbolinks-sucks/" rel="nofollow" target="_blank"&gt;http://saito.im/note/Turbolinks-sucks/&lt;/a&gt; …&lt;/p&gt;

&lt;p&gt;HN: &lt;a href="https://news.ycombinator.com/item?id=6043883" rel="nofollow" target="_blank"&gt;https://news.ycombinator.com/item?id=6043883&lt;/a&gt; &lt;/p&gt;</description>
      <author>Saito</author>
      <pubDate>Sun, 14 Jul 2013 23:57:13 +0800</pubDate>
      <link>https://ruby-china.org/topics/12507</link>
      <guid>https://ruby-china.org/topics/12507</guid>
    </item>
    <item>
      <title>The Ћ Symbol</title>
      <description>&lt;p&gt;&lt;span class="embed-responsive embed-responsive-16by9"&gt;&lt;iframe class="embed-responsive-item" src="//www.youtube.com/embed/KZRaxXC63RI" allowfullscreen=""&gt;&lt;/iframe&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <author>Saito</author>
      <pubDate>Fri, 05 Jul 2013 22:33:05 +0800</pubDate>
      <link>https://ruby-china.org/topics/12288</link>
      <guid>https://ruby-china.org/topics/12288</guid>
    </item>
    <item>
      <title>[杭州][端点网络科技有限公司] 前端 / 后端 Java 工程师</title>
      <description>&lt;h2 id="关于我们"&gt;关于我们&lt;/h2&gt;&lt;h3 id="我们是谁"&gt;我们是谁&lt;/h3&gt;
&lt;p&gt;6 位前阿里系员工组成的完整团队，包括资深架构师、视觉设计、PD 以及资深前/后端开发工程师，团队氛围良好。&lt;/p&gt;
&lt;h3 id="我们做什么"&gt;我们做什么&lt;/h3&gt;
&lt;p&gt;电商解决方案养活自己、O2O 平台努力创业中。&lt;/p&gt;
&lt;h3 id="我们给什么"&gt;我们给什么&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;行业内有竞争力的薪资&lt;/li&gt;
&lt;li&gt;有可能会很值钱的期权&lt;/li&gt;
&lt;li&gt;快速学习和成长的机会&lt;/li&gt;
&lt;/ul&gt;

&lt;hr&gt;
&lt;h2 id="招聘职位"&gt;招聘职位&lt;/h2&gt;
&lt;p&gt;我们希望招聘应届毕业生，但也不限于应届毕业生，如果您有兴趣欢迎联系。&lt;/p&gt;
&lt;h3 id="前端工程师"&gt;前端工程师&lt;/h3&gt;&lt;h4 id="技能要求"&gt;技能要求&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;能熟练使用 javascript、css 和 html 构建设计师给出的页面&lt;/li&gt;
&lt;li&gt;了解 jquery、underscore 等主流前端库、了解一种前端模板引擎例如 handlebars&lt;/li&gt;
&lt;li&gt;了解浏览器之间的差异，知道如何让你创造的东西在每一个浏览器上都有较一致的表现&lt;/li&gt;
&lt;li&gt;了解 css3 和 html5&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="比基本要求更重要的"&gt;比基本要求更重要的&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;具备发现问题根源和解决问题的思路，懂得去哪里找到需要的信息和帮助&lt;/li&gt;
&lt;li&gt;良好的沟通能力，乐观开朗的性格&lt;/li&gt;
&lt;li&gt;热爱自己创造的东西&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="这是附加题"&gt;这是附加题&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;知道并参与 &lt;code&gt;github.com&lt;/code&gt; 和 &lt;code&gt;stackoverflow.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;熟悉 coffee、less、sass 等提高生产率的工具&lt;/li&gt;
&lt;li&gt;熟悉 Java 或 Ruby&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="Java工程师"&gt;Java 工程师&lt;/h3&gt;&lt;h4 id="技能要求"&gt;技能要求&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;java 基础扎实，了解 util、collection、concurrent 包中的 api&lt;/li&gt;
&lt;li&gt;对至少一种 java web 框架、IOC 框架熟练使用，并了解其优缺点&lt;/li&gt;
&lt;li&gt;熟悉 sql， *nix 操作系统&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="比基本要求更重要的"&gt;比基本要求更重要的&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;具有自主学习及解决问题的能力，对新技术有好奇心，有热情&lt;/li&gt;
&lt;li&gt;关注代码质量，不拒绝重构甚至重写&lt;/li&gt;
&lt;li&gt;良好的团队协作能力，以及开放的心态&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="这是附加题"&gt;这是附加题&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;熟悉其他任意一种语言&lt;/li&gt;
&lt;li&gt;熟悉前端技术&lt;/li&gt;
&lt;/ul&gt;

&lt;hr&gt;
&lt;h2 id="联系方式"&gt;联系方式&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;email: &lt;code&gt;anson0370@gmail.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;发这篇东西的人的任何联系方式&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://gist.github.com/anson0370/5667855" rel="nofollow" target="_blank"&gt;https://gist.github.com/anson0370/5667855&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <author>Saito</author>
      <pubDate>Mon, 01 Jul 2013 14:35:42 +0800</pubDate>
      <link>https://ruby-china.org/topics/12142</link>
      <guid>https://ruby-china.org/topics/12142</guid>
    </item>
    <item>
      <title>Github Open Source Contributions Calendar.</title>
      <description>&lt;p&gt;Gist: &lt;a href="https://gist.github.com/SaitoWu/5599617" rel="nofollow" target="_blank"&gt;https://gist.github.com/SaitoWu/5599617&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Account: &lt;a href="https://github.com/SA1T0" rel="nofollow" target="_blank"&gt;https://github.com/SA1T0&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Graph: &lt;img src="http://d.pr/i/HHp2+" title="" alt=""&gt;&lt;/p&gt;</description>
      <author>Saito</author>
      <pubDate>Sat, 18 May 2013 17:35:13 +0800</pubDate>
      <link>https://ruby-china.org/topics/11082</link>
      <guid>https://ruby-china.org/topics/11082</guid>
    </item>
    <item>
      <title>Ruby 开发者沙龙资料篇...</title>
      <description>&lt;p&gt;&lt;a href="https://speakerdeck.com/saito/middle-scale-f2e-application" rel="nofollow" target="_blank"&gt;https://speakerdeck.com/saito/middle-scale-f2e-application&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="/Saito" class="user-mention" title="@Saito"&gt;&lt;i&gt;@&lt;/i&gt;Saito&lt;/a&gt; Middle-Scale F2E Application  =&amp;gt; Lightning Talk&lt;/p&gt;

&lt;p&gt;&lt;a href="https://speakerdeck.com/luikore/ruby-2-dot-1-walk-thru-title-bait" rel="nofollow" target="_blank"&gt;https://speakerdeck.com/luikore/ruby-2-dot-1-walk-thru-title-bait&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="/luikore" class="user-mention" title="@luikore"&gt;&lt;i&gt;@&lt;/i&gt;luikore&lt;/a&gt; Ruby 2.1 Walk Thru =&amp;gt; Session&lt;/p&gt;

&lt;p&gt;其他各位麻烦补充，我是来组成头部的...&lt;/p&gt;

&lt;p&gt;&lt;a href="/ShiningRay" class="user-mention" title="@ShiningRay"&gt;&lt;i&gt;@&lt;/i&gt;ShiningRay&lt;/a&gt; 屌丝程序员如何打造日 PV 百万的网站架构&lt;/p&gt;

&lt;p&gt;&lt;a href="https://speakerdeck.com/shiningray/diao-si-cheng-xu-yuan-ru-he-da-zao-ri-pvbai-mo-de-wang-zhan-jia-gou" rel="nofollow" target="_blank"&gt;https://speakerdeck.com/shiningray/diao-si-cheng-xu-yuan-ru-he-da-zao-ri-pvbai-mo-de-wang-zhan-jia-gou&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="/flyerhzm" class="user-mention" title="@flyerhzm"&gt;&lt;i&gt;@&lt;/i&gt;flyerhzm&lt;/a&gt; 构建异步 API 服务&lt;/p&gt;

&lt;p&gt;&lt;a href="https://speakerdeck.com/flyerhzm/gou-jian-yi-bu-apifu-wu" rel="nofollow" target="_blank"&gt;https://speakerdeck.com/flyerhzm/gou-jian-yi-bu-apifu-wu&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="/fsword" class="user-mention" title="@fsword"&gt;&lt;i&gt;@&lt;/i&gt;fsword&lt;/a&gt; 实践中的 CI &lt;/p&gt;

&lt;p&gt;&lt;a href="http://fsword.github.io/slide/ci_con/index.html" rel="nofollow" target="_blank"&gt;http://fsword.github.io/slide/ci_con/index.html&lt;/a&gt;&lt;/p&gt;</description>
      <author>Saito</author>
      <pubDate>Sat, 11 May 2013 21:56:59 +0800</pubDate>
      <link>https://ruby-china.org/topics/10906</link>
      <guid>https://ruby-china.org/topics/10906</guid>
    </item>
    <item>
      <title>Mac 用户快来滚雪球啊...</title>
      <description>&lt;p&gt;&lt;a href="http://macheist.com/" rel="nofollow" target="_blank"&gt;http://macheist.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;!![]((&lt;a href="http://d.pr/i/VBoy+" rel="nofollow" target="_blank"&gt;http://d.pr/i/VBoy+&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;xScope $30&lt;/p&gt;

&lt;p&gt;iStopMotion $50&lt;/p&gt;

&lt;p&gt;Totals $40&lt;/p&gt;

&lt;p&gt;Clarify $30&lt;/p&gt;

&lt;p&gt;Fantastical $20&lt;/p&gt;

&lt;p&gt;CleanMyMac 2 $40&lt;/p&gt;

&lt;p&gt;Little Inferno $10&lt;/p&gt;

&lt;p&gt;Path Finder $40&lt;/p&gt;</description>
      <author>Saito</author>
      <pubDate>Thu, 18 Apr 2013 16:41:58 +0800</pubDate>
      <link>https://ruby-china.org/topics/10308</link>
      <guid>https://ruby-china.org/topics/10308</guid>
    </item>
    <item>
      <title>Ruby memory leak detection</title>
      <description>&lt;h2 id="Ruby memory leak detection"&gt;Ruby memory leak detection&lt;/h2&gt;&lt;h3 id="ObjectSpace object count"&gt;ObjectSpace object count&lt;/h3&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;counts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Hash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="no"&gt;ObjectSpace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_object&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# or&lt;/span&gt;
&lt;span class="no"&gt;ObjectSpace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count_objects&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="Symbol count"&gt;Symbol count&lt;/h3&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# symbol will not be garbage collected&lt;/span&gt;
&lt;span class="no"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all_symbols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="Heap Dump"&gt;Heap Dump&lt;/h3&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# gem i heap_dump&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'heap_dump'&lt;/span&gt;
&lt;span class="c1"&gt;# will automatically run GC.start&lt;/span&gt;
&lt;span class="no"&gt;HeapDump&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dump&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="GC"&gt;GC&lt;/h3&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# check if its just not be garbage collected&lt;/span&gt;
&lt;span class="no"&gt;GC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="TracePoint on system hook"&gt;TracePoint on system hook&lt;/h3&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# hook on native events&lt;/span&gt;
&lt;span class="no"&gt;TracePoint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="nb"&gt;p&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lineno&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;enable&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hello_world&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"hello"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;hello_world&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="GDB &amp;amp; Dtrace(ruby 2.0)"&gt;GDB &amp;amp; Dtrace(ruby 2.0)&lt;/h3&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# I'm not a c guy. so...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上是我的一些笔记，结果我用了上面所有的方法，最终发现问题不是 memory leak..&lt;/p&gt;

&lt;p&gt;orz.&lt;/p&gt;</description>
      <author>Saito</author>
      <pubDate>Mon, 25 Mar 2013 15:54:15 +0800</pubDate>
      <link>https://ruby-china.org/topics/9737</link>
      <guid>https://ruby-china.org/topics/9737</guid>
    </item>
    <item>
      <title>[杭州][2013年3月5日] Ruby Tuesday 活动召集</title>
      <description>&lt;p&gt;时间&lt;/p&gt;

&lt;p&gt;2013-3-5 晚 7:00&lt;/p&gt;

&lt;p&gt;地点&lt;/p&gt;

&lt;p&gt;地址：杭州西溪路浙大科技园 c 栋 203 室&lt;/p&gt;

&lt;p&gt;主题&lt;/p&gt;

&lt;p&gt;暂定为：Saito 分享前端的一些想法与认识。&lt;/p&gt;

&lt;p&gt;地图：&lt;/p&gt;

&lt;p&gt;!![]((&lt;a href="http://d.pr/i/YoDj+" rel="nofollow" target="_blank"&gt;http://d.pr/i/YoDj+&lt;/a&gt;)&lt;/p&gt;</description>
      <author>Saito</author>
      <pubDate>Thu, 28 Feb 2013 12:52:30 +0800</pubDate>
      <link>https://ruby-china.org/topics/9006</link>
      <guid>https://ruby-china.org/topics/9006</guid>
    </item>
    <item>
      <title>gitlab-shell for gitlab v5.0</title>
      <description>&lt;p&gt;之前我分享过关于 gitlab 背后的一些小知识：&lt;a href="https://speakerdeck.com/saito/how-gitlab-works" rel="nofollow" target="_blank"&gt;https://speakerdeck.com/saito/how-gitlab-works&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;其中提到了 backend 部分如何实现。并且列出了 gitolite/gitsis, patch sshd, replace sshd  三种不同的实现举例..&lt;/p&gt;

&lt;p&gt;在即将发布的 gitlab v5.0 系列，gitlab 将完全移除对于 gitolite 的依赖。这个问题其实很早以前我们就讨论过。( Thread 是从下往上的顺序...&lt;/p&gt;

&lt;p&gt;&lt;img src="http://d.pr/i/gzxj+" title="" alt="twitter plus"&gt;&lt;/p&gt;

&lt;p&gt;当时的讨论最终我贡献了 gitlab 中 HTTP protocol 系列的访问，而 gitolite 没有被最终移除..&lt;/p&gt;

&lt;p&gt;gitolite 与 gitlab 的适配问题其实是导致很多人安装困难的主要原因，我当时提出的解决方案是 HTTP Only. 不过这个也不是一个完美的解决方案。终于在 5.0 移除了这个祸害..&lt;/p&gt;

&lt;p&gt;简单介绍一下 gitolite 与 gitlab-shell 的实现异同：&lt;/p&gt;

&lt;p&gt;首先他们都是 SSH-magic-command 的忠实信徒 ( 名词解释参考 slide. gitolite 最终将 command 导向了自己的 auth 程序。而 gitlab-shell 则用 gitlab 的 HTTPS API 去认证。&lt;/p&gt;

&lt;p&gt;gitolite 有自己的认证体系，所以之前与 gitlab 的结合需要冗余一份数据在 gitolite 里面，而异构系统之前的状态同步是"世界难题"... 所以经常会需要同步状态.. 而 gitlab-shell 则利用 mysql 内部的所有 Repo 认证信息来做认证，现在 HTTPS 与 SSH 的认证被统一在 Ruby 程序中了。&lt;/p&gt;

&lt;p&gt;gitolite 自身的配置文件是利用 git 管理的，而面对较大数据量的文件。性能极差... gitlab-shell 保守提高了 10x 的性能。&lt;/p&gt;

&lt;p&gt;其实这次 gitlab-shell 的调整也是因为 gitlab.com 本身在 randx 加入后，网站本身也在不断扩容。碰到了这样的性能问题，平时运维也出现了麻烦。所以才会做出这样的变化..&lt;/p&gt;

&lt;p&gt;随着 gitlab.com 越做越大。肯定会有更多的新东西出来..&lt;/p&gt;</description>
      <author>Saito</author>
      <pubDate>Fri, 22 Feb 2013 23:31:07 +0800</pubDate>
      <link>https://ruby-china.org/topics/8861</link>
      <guid>https://ruby-china.org/topics/8861</guid>
    </item>
    <item>
      <title>randx 加入 gitlab.com, 作为 co-founder 了.</title>
      <description>&lt;p&gt;1 year, 1 open source project, 1 future..&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ps: gitlab.com 本身不是 &lt;code&gt;GitlabHQ&lt;/code&gt; 控制的。&lt;code&gt;GitlabHQ&lt;/code&gt; 拥有 Gitlab.org 域名。&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <author>Saito</author>
      <pubDate>Thu, 24 Jan 2013 16:23:16 +0800</pubDate>
      <link>https://ruby-china.org/topics/8332</link>
      <guid>https://ruby-china.org/topics/8332</guid>
    </item>
    <item>
      <title>10 行令你朋友惊讶的 Clojure 代码</title>
      <description>&lt;p&gt;10 Clojure One Liners to Impress Your Friends&lt;/p&gt;

&lt;p&gt;I saw an interesting post today aptly titled 10 Scala One Liners to Impress Your Friends and then someone followed up with another blog post titled 10 CoffeeScript One Liners to Impress Your Friends. Those two posts show programming tasks (most of them trivial to solve in modern programming languages) being accomplished in about 1 line of code each.&lt;/p&gt;

&lt;p&gt;I thought it’d be quite appropriate if someone ported those examples to my favourite programming language Clojure, so here they are -&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Multiple Each Item in a List by 2&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Sum a List of Numbers&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reduce&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1001&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Verify if Word Exists in a String&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I used a regex here, because I believe that’s the right way to do it.&lt;/p&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tweet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"This is an example tweet talking about clojure and emacs."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;regex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;re-pattern&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;apply&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;interpose&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"|"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"clojure"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"logic"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"compojure"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"emacs"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"macros"&lt;/span&gt;&lt;span class="p"&gt;]))))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;re-seq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;regex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tweet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; Gives me the actual matches instead of just true/false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As suggested by a commentator, this problem can be solved without using regex by leveraging Clojure’s sets.&lt;/p&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tweet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"This is an example tweet talking about clojure and emacs."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;is-word?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"clojure"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"logic"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"compojure"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"emacs"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"macros"&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;nil?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;some&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;is-word?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;.split&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tweet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;" "&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; Returns true/false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Read a File&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file-text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;slurp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"data.txt"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; Reads the whole file&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;file-lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;clojure.contrib.io/read-lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"data.txt"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; Reads as a sequence of lines&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since Clojure Contrib has been deprecated for future Clojure releases, clojure.contrib.io/read-lines can be rewritten as (line-seq (clojure.java.io/reader (clojure.java.io/file “data.txt”))) in Clojure 1.3 onwards. Thanks to Aaron for pointing it out.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Happy Birthday to You&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;doseq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Happy Birthday "&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"dear Rich"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"to You"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Alternate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;-&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;dotimes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Happy Birthday "&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"dear Rich"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"to You"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Filter List of Numbers&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;partition-by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;49&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;58&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;76&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;82&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;88&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Fetch and Parse XML Web Service&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;clojure.xml/parse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"http://search.twitter.com/search.atom?&amp;amp;q=clojure"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Find Maximum (or Minimum) in a List&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reduce&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;46&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;98&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reduce&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;46&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;98&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;;; Now both together&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nf"&gt;juxt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reduce&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reduce&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;46&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;98&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; Returns [98 -7]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Parallel Processing&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="c1"&gt;;; Assuming process-line to be a CPU intensive function that operates on a line&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;pmap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;process-line&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;; Note the "p" in front of map&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Sieve of Eratosthenes&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I don’t I have a sufficiently good (in terms of performance &amp;amp; beauty) one line implementation of SoE. I would recommend checking out Christophe Grand’s treatise on the subject titled Everybody loves the Sieve of Eratosthenes for a great discussion on writing real world prime sieves in Clojure.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Solve FizzBuzz&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class="highlight clojure"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;#&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;cond&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;zero?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mod&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"FizzBuzz"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;zero?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mod&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Fizz"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;zero?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mod&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Buzz"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;:else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;101&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Conclusion&lt;/p&gt;

&lt;p&gt;Can’t conclude anything from these examples, really. Clojure is an extremely powerful and succinct programming language. Learn it, write some code in it and then decide for yourself.&lt;/p&gt;

&lt;p&gt;Have fun!&lt;/p&gt;

&lt;p&gt;Fork from: &lt;a href="http://freegeek.in/blog/2011/06/10-clojure-one-liners/" rel="nofollow" target="_blank"&gt;http://freegeek.in/blog/2011/06/10-clojure-one-liners/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;通过本帖可以同时学习到 CoffeeScript 与 Scala 10 技.. &lt;/p&gt;</description>
      <author>Saito</author>
      <pubDate>Thu, 10 Jan 2013 18:11:08 +0800</pubDate>
      <link>https://ruby-china.org/topics/7953</link>
      <guid>https://ruby-china.org/topics/7953</guid>
    </item>
    <item>
      <title>你必须知道的 Clojure ! </title>
      <description>&lt;h2 id="你必须知道的 Clojure ( 预告"&gt;你必须知道的 Clojure ( 预告&lt;/h2&gt;&lt;h3 id="Pattern Matching"&gt;Pattern Matching&lt;/h3&gt;
&lt;p&gt;; let for :as :or
    ; list vector set hash
    ; defrecord&lt;/p&gt;
&lt;h3 id="Function overloading"&gt;Function overloading&lt;/h3&gt;
&lt;p&gt;; defn
    ; defmulti defmethod&lt;/p&gt;
&lt;h3 id="STM ( Software Transactional Memory )"&gt;STM ( Software Transactional Memory )&lt;/h3&gt;
&lt;p&gt;; ref atom agent vars&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;底稿打了，还没写完。先让 Google 记一发！&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <author>Saito</author>
      <pubDate>Sat, 05 Jan 2013 17:35:47 +0800</pubDate>
      <link>https://ruby-china.org/topics/7753</link>
      <guid>https://ruby-china.org/topics/7753</guid>
    </item>
    <item>
      <title>难道你们还没学 Clojure ?</title>
      <description>&lt;p&gt;程序设计的美学都在这里了。&lt;/p&gt;

&lt;p&gt;贴一小段笔记：&lt;/p&gt;
&lt;h3 id="Data Structures:"&gt;Data Structures:&lt;/h3&gt;
&lt;p&gt;nil: &lt;code&gt;nil&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;char: &lt;code&gt;\c&lt;/code&gt; or &lt;code&gt;(char c)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;number: &lt;code&gt;1&lt;/code&gt; or &lt;code&gt;(num 1)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;string: &lt;code&gt;"abc"&lt;/code&gt; or &lt;code&gt;(str abc)&lt;/code&gt; ???&lt;/p&gt;

&lt;p&gt;keyword: &lt;code&gt;:a&lt;/code&gt; or &lt;code&gt;(keyword "a")&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;symbols: &lt;code&gt;'a&lt;/code&gt; or &lt;code&gt;(quote a)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;boolean: &lt;code&gt;false&lt;/code&gt; or &lt;code&gt;(boolean false)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;list: &lt;code&gt;'(1 2 3)&lt;/code&gt; or &lt;code&gt;(list 1 2 3)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;vector: &lt;code&gt;[1 2 3]&lt;/code&gt; or &lt;code&gt;(vector 1 2 3)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;hash: &lt;code&gt;{:a 1, :b 2}&lt;/code&gt; or &lt;code&gt;(hash-map :a 1 :b 2)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;set: &lt;code&gt;#{1 2 3}&lt;/code&gt; or &lt;code&gt;(hash-set 1 2 3)&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="Clojure Seq"&gt;Clojure Seq&lt;/h3&gt;
&lt;p&gt;ASeq
    LazySeq&lt;/p&gt;

&lt;p&gt;Seqable
    null
    Iterable
    Array
    CharSequence
    Map&lt;/p&gt;
&lt;h3 id="Seq Interface"&gt;Seq Interface&lt;/h3&gt;
&lt;p&gt;(first coll)&lt;/p&gt;

&lt;p&gt;(rest coll)&lt;/p&gt;

&lt;p&gt;(cons item coll)&lt;/p&gt;
&lt;h3 id="Seq Library"&gt;Seq Library&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;range&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;user=&amp;gt; (range 10)
    (0 1 2 3 4 5 6 7 8 9)
    user=&amp;gt; (range 1 10)
    (1 2 3 4 5 6 7 8 9)
    user=&amp;gt; (range 1 10 2)
    (1 3 5 7 9)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;repeat&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;user=&amp;gt; (repeat 10)
    (10 10 10 10 10 10 10 10 10 10 ...)
    user=&amp;gt; (repeat 1 10)
    (10)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;iterate&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;user=&amp;gt; (iterate inc 1)
    (1 2 3 4 5 6 7 8 9 10 ...)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;take&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;user=&amp;gt; (take 1 (repeat 10))
    (10)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;map&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;user=&amp;gt; (map #(* % 2) (range 1 10))
    (2 4 6 8 10 12 14 16 18)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;reduce&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;user=&amp;gt; (reduce + (range 10))
    45&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;for&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;user=&amp;gt; (for &lt;a href="*%20x%202" title=""&gt;x (range 1 10)&lt;/a&gt;)
    (2 4 6 8 10 12 14 16 18)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;filter&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;user=&amp;gt; (filter even? (range 10))
    (0 2 4 6 8)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;remove&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;user=&amp;gt; (remove even? (range 10))
    (1 3 5 7 9)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;replace&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;user=&amp;gt; (replace [1 2 3 4 5] [4 3 2 1 0])
    [5 4 3 2 1]
    user=&amp;gt; (replace ["a" "&amp;gt;" "b"] [2 1 0])
    ["b" "&amp;gt;" "a"]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;cycle&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;user=&amp;gt; (cycle [0 1 2])
    (0 1 2 0 1 2 0 1 2 0 ...)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;reverse&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;user=&amp;gt; (reverse (range 10))
    (9 8 7 6 5 4 3 2 1 0)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;shuffle&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;user=&amp;gt; (shuffle (range 10))
    [1 4 8 0 6 3 9 2 5 7]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;sort&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;user=&amp;gt; (sort (shuffle (range 10)))
    (0 1 2 3 4 5 6 7 8 9)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;flatten&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;user=&amp;gt; (flatten '(1 &lt;a href="4%20[5%206]" title=""&gt;2 3&lt;/a&gt; 7 8 [9]))
    (1 2 3 4 5 6 7 8 9)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;distinct&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;user=&amp;gt; (distinct [1 2 3 1 2])
    (1 2 3)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;interleave&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;user=&amp;gt; (interleave [:a :b] [1 2])
    (:a 1 :b 2)
    user=&amp;gt; (interleave &lt;a href="iterate%20inc%201" title=""&gt;:a :b :c&lt;/a&gt;)
    (:a 1 :b 2 :c 3)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;interpose&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(interpose "," [:a :b :c])
    (:a "," :b "," :c)
    user=&amp;gt; (apply str (interpose ", " [:a :b :c]))
    ":a, :b, :c"&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;into&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;user=&amp;gt; (into (reverse (range 5)) (range 5 10))
    (9 8 7 6 5 4 3 2 1 0)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;split-at&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;user=&amp;gt; (split-at 5 (range 10))
    [(0 1 2 3 4) (5 6 7 8 9)]&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;partition&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;user=&amp;gt; (partition 2 (range 10))
    ((0 1) (2 3) (4 5) (6 7) (8 9))
    user=&amp;gt; (partition 2 3 (range 10))
    ((0 1) (3 4) (6 7))
    user=&amp;gt; (partition 2 3 &lt;a href="range%2010" title=""&gt;10&lt;/a&gt;)
    ((0 1) (3 4) (6 7) (9 10))&lt;/p&gt;
&lt;h3 id="-&gt;"&gt;-&amp;gt;&lt;/h3&gt;
&lt;p&gt;user=&amp;gt; (-&amp;gt; 5 (+ 2) (- 3) (* 2))
    8&lt;/p&gt;

&lt;p&gt;user=&amp;gt; (-&amp;gt; "x y z" .toUpperCase (.replace "X" "A") (.split " ") first)
    "A"&lt;/p&gt;

&lt;p&gt;新纪元下你还抢着学 Go? 醒醒吧!...&lt;/p&gt;

&lt;p&gt;Clojure Document: &lt;a href="http://clojure.org/documentation" rel="nofollow" target="_blank"&gt;http://clojure.org/documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clojure Docs: &lt;a href="http://clojuredocs.org/quickref/Clojure%20Core" rel="nofollow" target="_blank"&gt;http://clojuredocs.org/quickref/Clojure%20Core&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clojure Cheatsheet : &lt;a href="https://github.com/jafingerhut/clojure-cheatsheets/tree/master/pdf" rel="nofollow" target="_blank"&gt;https://github.com/jafingerhut/clojure-cheatsheets/tree/master/pdf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clojure koans : &lt;a href="https://github.com/functional-koans/clojure-koans" rel="nofollow" target="_blank"&gt;https://github.com/functional-koans/clojure-koans&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clojure ring( like rack ): &lt;a href="https://github.com/ring-clojure/ring" rel="nofollow" target="_blank"&gt;https://github.com/ring-clojure/ring&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;From Narkoz&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Clojure style guide: &lt;a href="https://github.com/bbatsov/clojure-style-guide" rel="nofollow" target="_blank"&gt;https://github.com/bbatsov/clojure-style-guide&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ruby + Clojure: &lt;a href="https://github.com/rouge-lang/rouge" rel="nofollow" target="_blank"&gt;https://github.com/rouge-lang/rouge&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;发文前在本地打底稿多么地重要！&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <author>Saito</author>
      <pubDate>Sat, 05 Jan 2013 17:23:20 +0800</pubDate>
      <link>https://ruby-china.org/topics/7750</link>
      <guid>https://ruby-china.org/topics/7750</guid>
    </item>
    <item>
      <title>enjoy your new rubby guys</title>
      <description>&lt;p&gt;&lt;a href="http://bugs.ruby-lang.org/issues/4085#change-34117" rel="nofollow" target="_blank"&gt;http://bugs.ruby-lang.org/issues/4085#change-34117&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;issues 4085 信息量非常大，足够你无聊看一天的。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="tl;dr"&gt;tl;dr&lt;/h3&gt;
&lt;p&gt;Refinements 的 spec 是不明确的，但是 ruby 2.0 一定要在 20 周年的时候发布。&lt;/p&gt;

&lt;p&gt;所以 matz 决定就这样了.. .&lt;/p&gt;

&lt;p&gt;JRuby 跟 Rubinus 的 leader 都反对或建议推迟 Refinments 在 Ruby 2.0 里面出现。&lt;/p&gt;

&lt;p&gt;headius: &lt;a href="http://blog.headius.com/2012/11/refining-ruby.html" rel="nofollow" target="_blank"&gt;http://blog.headius.com/2012/11/refining-ruby.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;brixen: &lt;a href="https://speakerdeck.com/brixen/toward-a-design-for-ruby" rel="nofollow" target="_blank"&gt;https://speakerdeck.com/brixen/toward-a-design-for-ruby&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;新的 rubby 2.0 . 你准备好了么？&lt;/p&gt;</description>
      <author>Saito</author>
      <pubDate>Thu, 29 Nov 2012 14:38:08 +0800</pubDate>
      <link>https://ruby-china.org/topics/7189</link>
      <guid>https://ruby-china.org/topics/7189</guid>
    </item>
  </channel>
</rss>
