Good good study, day day up

aleung的学习笔记, aleung的idea

Jekyll 与 Swagger UI 集成

| SoftwareDev

Swagger 是被广泛使用的用于 REST API 描述和文档化的框架。它制定了一个用于描述 REST API 的规范,提供了一组工具用于编辑 API 描述文件、生成测试客户端、生成文档等等。Swagger UI 是其中的用于生成文档的工具。

Jekyll 是深受程序员喜爱的静态网站生成工具,通常用来做 blog 站点,我们的工作团队也用它来做内部的技术文档库

在 Jekyll 里描述我们产品的 REST API,编辑排版是比较繁琐的事情,不同的 API 描述也没有统一的风格,因此考虑到引入 Swagger 来规范化 API 定义。

为此,写了一个简单的 Jekyll 插件,只要在 markdown 中简单的插入 swagger tag,指定 API 描述文件,相应的 API 文档就会由 Swagger UI 生成并嵌入在页面中。

{% swagger /api/my-api.json %}

安装使用方法请参看 README。另外,Swagger UI 没有考虑到在一个页面中显示多组 API,会有些显示问题,已经提交 pull request,下个版本有望修复,暂时可以先下载我的修改版本,详见 README。

几条基础排版规则,让文档显得专业

| Blogging

虽然我不是处女座的,但在有些事情上会表现得比较处女座,例如对于文档格式,我常会跟各种细节纠缠不休,为的是看起来显得完美一些。

作为软件开发者,写文档是必备的技能,而且文档里常常会出现大量英文。这里介绍一些很基本的规则,使得文档的显得专业一些。这些规则在其他类型的文章里也是适用的。

规则

用段落,不要强制换行

在我看来,禁止使用强制换行,是没有特例的(我们不写诗歌)。在必须保留原始换行的地方,应该作为 preformatted text block(HTML 的 PRE,markdown 的 4 空格缩进段落)出现。

保持一致性

保持标点、字体等元素的一致性,整篇文档看起来清晰整齐,可读性高。

在这方面常见问题有:

中文英文标点混用

写技术文章,经常会出现中文英文(西文)混合的场景。原则应该是在中文句子中使用中文标点,西文句子中使用西文标点。至于中文句子中嵌入西文引文,那么嵌入的西文内容中应该遵循西文引文这个“亚环境”的规则,用西文标点,但用来包裹嵌入内容的引号或者括号还是属于中文句子的环境,因此用中文标点。

简体繁体中文混用
这个如果不考虑海外用户,问题也不算大,对大陆读者来说,混合简体繁体阅读起来基本上没有违和感。
全角半角混用
除了中文标点外,西文字母和数字这些字符是不应该出现全角的。
成对的符号没有对称
例如引号,是区分左引号和右引号的,一般输入法会正确识别方向,但在拷贝粘贴或者插入编辑的时候要小心方向不要弄错。

空格的使用

中文标点不需要加空格。西文标点后需要加一个空格;成对的符号,开始的要在前面加空格,结束的在后面加空格。

西文单词之间要用空格分隔,这个不容易错。但是单词与数字之间也要加空格,例如“iPhone 6”。

中文与西文混排时,中文与西文之间可能要添加空格,以保证有一定间距,具体视乎显示效果而定。有人习惯一律加空格。1 2

西文大小写不要误用

强调以下的规则似乎有点小题大做,但确实还是经常会见到这样的错误。

  • 句子首字母大写,句子内不应该用大写,除非下面的情况;
  • 有些专有名词首字母大写的,即使用在句子中间也要保留大写;
  • 全部大写的缩写,放在哪里都不能变成小写。

西文没有书名号

书名号是中文特有的。在西文中,书名用斜体表示,篇名用引号。

使用样式,不要在文字上添加格式

同样语义的文字,就应该有同样的显示效果,这也是一致性的体现。把文字变得五颜六色,再插一段超大字体,这种做法还是留在小毛孩的论坛里吧。

不要滥用强调

强调会吸引注意力,打破文档视觉结构,只应该用在真正需要的地方。满篇的强调等于没有强调。

若要突出文档架构,应该使用标题(headings)。当文章中有些整行文字需要强调时,往往是应该将它们作为小标题。

在西文中,按照强调的程度不同,一般强调用斜体,特别强调用加粗。但是,斜体只适合西文,中文不好看,在印刷中可以用楷体或者加着重号代替,不过在一般电子文档中不方便使用(在 web 上可以用 CSS 来控制),没有什么好方法,所以在中文中就没法区分一般强调和特别强调了。 3

改颜色改字体大小之类的奇淫技巧不可使用。

合理使用格式

通过合理使用语义化的格式,可以达到需要的显示效果,而不用去直接指定如何显示。HTML 和 markdown 都支持以下几种格式:

引用 (blockquote)
整段文字引用自其他地方。
Preformatted text block
保留原始格式,包括换行,空格等。
代码格式
用等宽字体(monospaced font)显示。要做得漂亮一点就是加上自动语法高亮渲染了。
定义列表 (definition list)
适用于一个名词,后面一段解释的场合,就像现在这段文字。也就是 key-value map 在文本中的体现。在HTML 里是 DL, DTDD 标签,不属于基本的 markdown 格式,有些引擎会支持。

总结

保证各种元素的一致性。关注内容的层次结构,段落或文字的语义属性,而不是显示效果。显示效果由样式来控制。


Jekyll

| Blogging

用 Jekyll 作为内部技术文档库

去年在公司的产品开发团队中推行了使用 Jekyll 静态网站生成工具来写内部技术文档,大半年下来,效果还不错。

内部技术资料的共享和维护以前一直是个问题。开始用 Office Word 正正规规的写设计文档,维护成本太高了,往往是代码已经翻天覆地变化,文档里都没有反映出来,大家不愿意更新。而且查找起来也不方便。后来推行敏捷方法,不想让文档工作那么 heavy 了,于是用 wiki 来记录。Wiki 的问题是信息非常碎片化,大家很随意的添加新页面,整个 wiki 就像一个草稿本,写得很没有系统。网状的超链接导航令读者很迷茫,不知道需要的信息入口在哪儿,有些隐藏得很深的页面没有几个人知道它们的存在。Wiki 的在线编辑体验也不是那么好。

Jekyll 是个静态网站生成工具,采用 markdown 语法来写内容,根据模板生成 HTML 页面,发布到一个 web 服务器上,就可以用浏览器在线查看内容。Jekyll 通常用来做 blog 系统,但它用来做有组织的内容发布系统也是完全胜任的。我基本上就是仿照 Jekyll 官方文档 的风格和结构来组织我们产品的内部技术文档库。

使用 Jekyll 优点首先是编写方便,markdown 是个轻量的标记语言,上手简单,语法易记,而且有不少编辑工具支持。即使没有渲染成 HTML,也是直接可以阅读的,比起奇奇怪怪还各自不同的 wiki 语法好写多了。

在模板做得好以及安装合适的插件后,生成的文档显示效果相当漂亮,格式效果也很丰富。而且,我们使用了 plantuml 插件,可以直接用文字的方式UML1,比起以前用其他工具画图,截图,再嵌入文档这种方式方便多了。

技术文档库的原始文件是文本格式,用 git 来做版本管理,不用担心大家同时编辑保存时会相互覆盖的问题,修改历史也很清晰。大家都是程序员,本来代码就是用 git 来管理的,文档也用 git 管理自然是很顺手的事情。使用 jekyll-post-revision 这个插件,能够在生成的页面上显示修改历史记录。

通过 jekyll-lunr-js-search 这个插件,能为站点提供全文搜索的能力,这也是相当方便的功能。

在 Windows 上安装 Jekyll

Jekyll 是用 Ruby 开发的,在 Linux 和 Mac OS X 上安装使用都很简单,在系统中有 Ruby 环境的前提下(Mac 是自带的,Linux 的各种发行版都会有安装包),照着官网上的介绍,几个命令就搞定了。但是,在 Windows 下就不是那么简单了(顺便再黑一下 Windows,不使用 Microsoft 技术的开发者都应该离开它)。

在 Windows 上装过几次 Jekyll,可以写点教程减少大家摸索的时间。大致参考这篇 Run Jekyll on Windows

安装 Ruby

首先需要安装 Ruby 环境。从 http://rubyinstaller.org/downloads 下载 Ruby 2.0 和 DevKit,安装 Ruby,然后将 DevKit 解压到 C:/RubyDevKit,在命令行运行下面指令完成安装。

1
2
3
cd C:\RubyDevKit
ruby dk.rb init
ruby dk.rb install

安装 Jekyll 相关的 gem

Gem 是 Ruby 的包管理工具。在命令行执行gem install可从互联网的仓库直接下载和安装需要的包。如果需要代理,需要先设置环境变量http_proxy,如不需要则忽略第一行。其中,jekyll这个 gem 是必须安装的,其他的视乎环境、配置和使用的插件,可能需要装,可能不需要装。

1
2
3
4
5
6
7
8
9
10
set http_proxy=http://my-proxy:8080

gem install jekyll

gem install kramdown
gem install pygments
gem install nokogiri
gem install coderay
gem install wdm
gem install json

如果在安装过程中出现 SSL 错误,从这里可以找到解决方法。

使用 Jekyll

Jekyll 的相关操作都是执行jekyll命令进行。后面的基本上就是看官方文档慢慢折腾了。

制作 jekyll.exe

上面的步骤还是有点繁琐。我们公司里的都是 Java 程序员,在电脑里装个 Ruby 环境也没有其他用处。为了推广使用,简化大家的操作,做一个 portable 的 Jekyll 可执行程序会更好。

制作的步骤基本上参考这篇 Building Jekyll.exe for Windows

首先要安装 OCRA。可能还需要安装 psych,bigdecimal 这些 gem。

1
gem install ocra

解开 jekyll 到一个临时目录:

1
gem unpack jekyll

修改bin/jekyll,在开头增加几个依赖声明:

1
2
3
require 'nokogiri'
require 'jekyll-watch'
require 'wdm'

生成 exe 文件:

1
ocra --add-all-core --gem-all bin/jekyll lib/jekyll/mime.types lib/site_template/**/* lib/site_template/*

做出来的 jekyll.exe 需要测试一下,看看各种命令是否都能正常。视乎配置和使用插件的不同,可能需要增加更多的依赖声明。以上只是我的环境的例子,不一定适用于所有场景。

最后,我知道大家都还是懒得衣来伸手饭来张口的,就提供一个编译好的 jekyll.exe 下载,支持 kramdown 和 coderay。但还是那句话:不一定符合你的环境。


同事们关于 FP 语言的讨论

| Haskell, Scala, SoftwareDev

之前在公司里一来一往的邮件讨论,被江南白衣集成一篇收录到他的博客里,读下来还蛮有意思,转过来,以下为全文引用。其中的梁君就是我啦。

缘起

达夫君

利用 GitHub 统计分析编程语言发展趋势

第一轮讨论

梁君

增加的Java的项目里,不知道有多少是与Android相关的呢?

Scala最热门都是在意大利城市(Milan, Rome, Florence, Naples,Turin),很奇怪,意大利软件业不发达。于是查了字典在意大利语里scala是scale(英语)的意思,应该跟编程语言无关。排除之后排首位的就是 San Francisco和San Jose,硅谷地区。

最近几天在看 Haskell,真是非常有趣的一门语言。 于是也在Google Trends上看一下,搜索Haskell最热的城市是 Gothenburg,第二是Utrecht (因为乌特勒支大学?)。

2014年热度,按国家排序,Haskell最热也是China! 考虑到中国已经屏蔽了Google,这个结果令人吃惊。在国内Scala, Haskell也不是那么热门吧?程序员人口基数大?

雄君

Haskell应该是所有程序语言里面被神化的最厉害的吧。有种说法,Haskell可以让你变成一个更好的程序员,即便你不用它,好像还有本书名就是这个。感觉看几本Haskell书就能变成高手似的,快变成宗教了都。。。。

梁君

Haskell应该是一种研究型/教学型语言吧。

据说是纯粹的FP,我现在看它是想试试强迫一下自己使用FP的思维模式。

那篇 WhyWhyFP 不错。 里面,看到一些话(虽然不算是那篇文字的主题):

The key is the word better. It is not the same as the phrase more powerful. it is possible to make a language “better” by removing features that are considered harmful, if by doing so it makes programs in the language better programs.

关于 better 与 powerful 的思考,不是功能越多就越好。用在我们的产品上也是一样啊。

哥德堡的Haskell教授

赵君

Gothenburg研究Haskell的那个人好像是Richard君的教授。感兴趣的可以问问Richard的感受。

范君

Richard说的:

Mr Hughes is a very smart guy. And his homepage hasn’t changed since I had him as a professor : http://www.cse.chalmers.se/~rjmh/

国外大学很多都是用Haskell,大老板之前去大英帝国读研也是用它。

FP做题大赛

韶君

我好奇看一下,“证明即程序、命题为类型”,这就是一门数学领域的领域语言,难怪学院派对它宠爱有加,一边证明一边编程,逼格高啊

有个网站号称趣味学Haskell: HASKELL 趣學指南 1

Step by step 学了一下Haskell,居然停不下来,无论写还是读,都像在玩puzzle game,都想找回以前的数学课本来复习一下。我想不用也能让你成为更好的程序员此话不假,就是让你恶补一下已经还给老师的数学概念。

给个零零漆的经典应用题大家思考一下:有一个农场,鸡的数目是鸭的四倍,但是鸭又比猪少九只,鸭和猪的数目是六十七只,请问农场所有动物的脚加起来共多少只?

雄君

感觉这跟你的学习方式关系更大,跟语言关系不大的。你也可以用Scala去做SICP的习题,同样有这种感觉。

梁君

不挑起具体语言之争。韶君的例子应该是说明FP给人带来耳目一新的感觉。

另外,我感觉那本书 (Learn You a Haskell) 用来做FP入门真的很好,之前看过一些Scala的书都没有那么清晰的理解。

顺便做做那道题目:

1
2
Prelude> head [c*2+d*2+p*4 | d<-[0..], let c=d*4, let p=d+9, d+p==67]
442

韶君

我原来写的是

1
head [a*2+b*2+c*4|a <-[1,2..], b <-[1,2..], c <- [1,2..], a=4*b, b=c-9, b+c=67]

结果不会结束,除非数组加上限,有空找你理解一下。

确实是FP带来的感觉,相信Scala也可以带来这个感觉,只不过如果我用Scala就不自觉地当Java来做了。

达夫君

我原来也是将Scala当Java来写。但是当你将Java的语法忘了差不多了,Scala就入门了:)

其实只是个老问题,就是平常没机会看Scala的代码,没有好的example参考而已。 看别人的代码多了,也就习惯了。

用 Scala 解那道题:

1
2
3
4
5
6
7
8
9
val d = (1 to 67) toStream
val feet = for {
  d1 <- d
  c1 = d1 * 4
  p1 = d1 +9 if (d1 + p1 == 67)
} yield {
  (c1+d1) * 2 + p1 * 4
}
println(feet.take(1).force)

梁君

Scala应该增加一种纯FP模式,当打开这个选项的时候,任何不符合FP的写法都报错(或者warning)。

米君

沒電腦,裸寫一段 Python,不知道對不對:

1
print map(lambda x: x*2 + x*4*2 + (x+9)*4, filter(lambda x: x+x+9 == 67, range(0,67)))[0]

看起來還是 Haskell 的最有數學味。

邊打邊爐邊研究,或者還可以這樣(不知道對不對,大意如此):

1
print (x*2 + x*4*2 + (x+9)*4 for x in range(0, 67) if x+x+9 == 67)[0]

據說這樣有 lazy evaluation,map 和 filter 不知道有沒有。有明白人指點一下嗎?

韶君

FP的思路就是“是什么”,指令编程的思路是“做什么”,从这个角度看 head [c*2+d*2+p*4 | d<-[0..], let c=d*4, let p=d+9, d+p==67] 这个最优雅了,基本上把题目复述一遍而已

雄君

米君,你已经线下把三元方程转成一元了,这个是作弊吧,不算。

Haskell的 lazy evaluation 在这么小的程序里面也会搞出无限循环的bug,这是它没法商用的最大原因之一。

我发一个Clojure的,也符合数据的解方程思路。

1
2
3
4
(first (for [p (range 1 67)
             :let [d (- 67 p) c (* 4 d)]
             :when (= d (- p 9))]
         (+ (* p 4) (* d 2) (* c 2))))

梁君

这个我忍不住要说说了,上限没有在原题中给出,需要推理才能得到的。Haskell的程序里是没有设上限的:a <-[1..], b <-[1..], c <- [1..]。 你们写的其他程序都是有上限的:p (range 1 67)x in range(0, 67)(1 to 67)

用这个来说Haskell会搞出无限循环的bug是不是有点冤枉了?

p.s. FP的理论在那里,现代的语言都或多或少吸取进去了,只是用什么语法形式的问题,纯粹一些还是要跟原来的特性做妥协,大家也都相互借鉴。除了Java最不思上进。

看上去Clojure的语法最像Lisp。

米君

不服上訴。哈哈。

這樣呢?算不算真三元?(已經盡力了。除非改成一元,否則range 好像是繞不過的坎,如果改成無限列表也是一樣會死循環。)

1
print iter( c*2 + d*2 + p*4 for c in range(67*4) for d in range(67) for p in range(67) if c == d*4 and d == p-9 and d+p == 67).next()

Clojure的版本和Java看上去很像啊。唯一不同大概就是 lazy evaluation 吧。 另外,雖然定義了三個變量,但其實只有一個是真正的“變”量,所以還是一元。

1
2
3
4
5
6
for ( int p = 1; p <=67; d++) {
  int d = 67 - p;
  int c = d * 4;
  if ( d == p - 9 )
    System.out.println( c*2 + d*2 + p*4 )
}

雄君

其实完全不是那么一回事,Scala和Clojure里面的for不是循环的意思,达夫之前解释过。这是Java程序员转FP的第一重障碍。另外,Clojure这段代码绝对没有lazy evaluation,如果需要Lazy,Clojure必须要明确指定使用Lazy seq。

Python和Java的表达能力不可能赶上Lisp的,超过Lisp表达能力的语言还没有发明出来。

最后一轮讨论

雄君

Clojure是一个Lisp变种,也是目前唯一的一个商业化的Lisp系语言。

Haskell 是 lazy evaluation by default 的语言,全世界几乎独此一家了。这个特性导致程序运行时,时间和空间都是不可预期的,基本上没有企业敢用。

Haskell又为了程序在逻辑上的predictable,从语言成面回避side effect,结果连个随机数生成都搞不定,发明monad来解决这个问题。问题是monad这么复杂的东西,用Haskell开发竟然是必须掌握的技巧,这很恐怖啊,哪找程序员?

这语言真的是只能看的。

韶君

Haskell我觉得商业上想取得成功确实不容易,但我不觉得作者想这样做,说商用,有哪种语言比Java更成功呢,指令语言也没那么容易出错,因为指令语言只有想不到,没有做不到,想取得商业成功就意味着妥协,从这个角度,我更看好Scala。

达夫君

估计等大家要看Java8的时候就需要考虑是升级JDK到8呢还是换Scala了。

梁君

Haskell 就是一门教学/研究型语言,开个学术会议,几个老家伙聚在一起,说不如我们设计个语言来显示一下FP多牛B吧。商业成功不是它设计的初衷 (后来其他人怎么想是另外一回事)

At the conference on Functional Programming Languages and Computer Architecture (FPCA ‘87) in Portland, Oregon, a meeting was held during which participants formed a strong consensus that a committee should be formed to define an open standard for such languages. The committee’s purpose was to consolidate the existing functional languages into a common one that would serve as a basis for future research in functional-language design.

才发现BASIC不是我唯一的入门语言,我刚学电脑的时候还看过Logo语言,这么说我也是一开始就接触FP的啦。

对Java程序员和已经大量投资于Java的软件企业来说,应该是Scala最有价值。

雄君

我是前几年被人忽悠后花了好几个月学习Haskell,还想用它做项目,现在已经弃坑了。

诗一首

孤独时

孤独时我不喜欢使用语言。
一头熊和一只鹦鹉坐在
跷跷板的两头
跷跷板朝一头翘起。很多东西
没办法称量,我是熊你们是鹦鹉。
我是这头熊我不使用
你们的语言。

余怒,2003.7.20

  1. 英文原版为 Learn You a Haskell for Great Good!。有电子书,简体中文纸板也出版了。

Haskell

| Haskell, SoftwareDev

2014年断断续续学了一阵子 Scala 语言,Scala 真的不错,将面向对象和函数式编程两种范式结合得很好,对 Java 程序员非常友好。不过,从学编程开始就受命令式编程的思想的浸淫,要使用函数式编程的思想相当困难,思路转不过来,而 Scala 又不强迫你用 FP,所以写出来的程序基本上还是命令式的。不少人都推荐学 Haskell 作为函数式编程的入门,作为一门学院派的语言,它非常纯粹,有助于掌握函数式编程的思维方式。于是开始读 Learn You a Haskell for Great Good,这真是本入门好书,从头开始一点点的理解接受函数式编程的思路。学 Haskell 的感觉非常有趣

不过那本书只是讲语言特性和思想,没有讲 Haskell 的运行环境和使用。上网收集了一些资料,记录下来。

Haskell (缺省)是编译成 native code,并非运行在托管环境下,因此开发出来的程序就像 C 的一样直接可执行的 binary。Haskell 程序需要依赖于 Runtime System (RTS),RTS 提供了内存管理,GC,轻量线程,并发等等功能的支持。包括 RTS 和其他的依赖到的 library,缺省都是静态链接到可执行程序中的,因此编译出来的程序体积会比较大。但现在 GHC 也已经支持动态链接了,如果使用动态链接,则要求运行环境中需要已经安装了 GHC(有 RTS)。在这方面,Haskell 跟 Go 差不多,都是直接得到 native 可执行程序,分发和部署会简单一些。

Haskell 的编译器叫做 Glasgow Haskell Compiler (GHC),它包括了 compiler,boot library 和 runtime system (RTS)。编译器支持多种 backend,除了可以生成 native code (机器码),也可以产生 C 语言源代码(供跨平台移植),或者 LLVM code,(供后面接 LLVM toolchain 使用)。

做应用开发不太可能什么都从头做起,必然要依赖第三方的函数库。Haskell 世界里的包管理和 build 系统叫 Cabal。另外有个工具 Cabal-Install 负责下载 Haskell package 源代码、编译、安装和注册到 GHC 的整个过程。共享的包存放在 Hackage 这个在线仓库中。

Reference: The Architecture of Open Source Applications - GHC