zoukankan      html  css  js  c++  java
  • 谈谈编译和运行

    在上一篇谈 API 的撰写 - 架构 文章里讲到:

    通过这样一个接口,我们把 API 系统区隔为「编译时」和「运行时」。这个接口写出来的 API,更像是一个等待编译的源文件。在 API 系统启动的时候,会经历一个「编译」的过程,把所有的 route 汇总起来,生成 restify 认识的路由形式,同时,收集里面的各种信息(比如 validator,authentication),供框架的各个 middleware 使用。

    「编译」(compile)是软件系统的一个非常非常重要的概念;很可惜,在 python / ruby / javascript 等解释型语言大行其道的当下,很多人已经不知道编译为何物。当然,即便你使用 c / go / java 等编译型语言,有多少人又真正清楚「编译」究竟是个什么过程呢?

    在 wikipedia,compile / compiler 的解释如下:

    A compiler is a computer program (or a set of programs) that transforms source code written in a programming language (the source language) into another computer language (the target language), with the latter often having a binary form known as object code.[1] The most common reason for converting source code is to create an executable program.

    所以 compile 实际上是一种 transformation(我们又见到这个词了):它把某个数据(如果你认为源代码也是一种数据的话)从一种格式转换成另外一种格式。在编译型语言里,这种转换是为了生成机器码(如 c / go),或者 byte code(java / c#),方便机器执行(byte code 会进一步以 JIT 的方式 compile 成机器码)。

    (题外话:其实解释型语言也是有一个 JIT 「编译」的过程;现在纯粹的,完全在运行时一句句解释执行的语言,只能生存在象牙塔里)

    有了这样一层(indirection)编译的过程,源数据和目标数据就被分离开,可以做很多事情,比如 wikipeidia 上说的 compiler 的一大功效:

    Compilers enabled the development of programs that are machine-independent.

    这里面,这个 machine-independent 可以根据你的需要被换成 framework-independent,甚至 language-independent。

    那么,一份源代码除了可以生成目标代码(主产品)外,还能有什么副产品?我们以 java 为例:

    • 如果你的注释遵循 javadoc,那么从代码里可以生产出来漂亮的文档(SDK)。

    • facebook/infer 可以对你的代码做详细的 static analysis。

    • jacoco 可以根据源码和 test case 生成 coverage report。

    • ...

    这些副产品带啦的好处是显而易见的:我们不用为了一些特定的目的而做一些额外的事情。

    回到我们说的 API 系统。我提到了这样的一个接口:

    你可以将其看做是一段声明 API 的代码,但我更愿意将其看做是一段描述 API 的数据。这个数据有:

    • method:API 使用何种 http 方法调用。

    • path:API 使用什么样的 endpoint。

    • description:API 的文档。

    • validators:如果要验证 API 的输入数据,如何验证。

    • action:API 具体做些什么事情。

    • flags:API 有哪些属性(需不需要验证,支不支持某些特定的操作等)。

    如果你以数据的眼光看待这段代码,那么,每一个 route() 的声明都可以被聚合起来,放到一个数组里。事实上,route 的实现就是如此:

    每当用户撰写一个 route 的时候,我们实际上在往一个 list 里 push 这个 route 的数据。这个 list 究竟怎么用,是生成 restify 的 route,还是生成 hapi 的 route,我们在编译时再具体决定。这便是 framework-independent。

    那么,什么是编译时,什么又是运行时呢?

    就这么简单。app.compile() 把放在 route list 里面的数据转换成 restify 的 route,而 app.run() 开始进行网络监听。很多同学看到这里会想,有没有搞错,我还以为是什么高深的东西呢,这代码我也会写啊。的确,这里没有任何高深的东西。然而,关键的是你会不会想到把一段代码的运行分解成:compile() 和run() 两个阶段。只有你这么去想了,你才会反过来考虑你的 API 的代码能不能退一步,用一个数据结构封装,你才会想这个数据结构该如何设置,你才会把 route() 的实现写成类似的方式。

    在「编译时」你可以做很多繁杂的事情,就像高手过招前先养气御剑一样;这样,在「运行时」,你才能打出行云流水的招式。

    再举一个例子。就写 blog 而言,你可以用 wordpress,也可用 jekyll 这样的 static site generator。前者把编译和运行混在一起,在请求页面的时候生成博文;而后者则将二者完全分离,你得使用 jekyll 的工具把 markdown 撰写的博文编译成 html,才能被正常访问。这样分离之后,天地开阔了很多,你可以在「编译时」为所有文章生成全文搜索所用的索引,可以根据文章的类别 / tag 生成目录,相关文章,菜单等等,在为运行时提供了闪电般的速度外,还能提供 wordpress 才能提供的动态性和灵活性。

    注意,这里所说的分离完全是逻辑上的分离,就像上一篇文章中的 pipeline,每个 component 是逻辑上单独存在,未必需要物理上完全分离。

    把「编译时」和「运行时」分离,是一项很重要的抽象能力。

  • 相关阅读:
    iOS万能跳转界面的方法
    CocoaPods版本更新
    iOS--开发小技巧(持续更新)
    RunTime--手势应用场景(很方便)
    牛逼的标签效果(封装好)
    直播点赞动画
    UI基础--自定义UISwitch
    StatusBar 更改状态栏颜色(ios7)
    ios版本更新提示
    IOS 两个UIImage 合成一个Image
  • 原文地址:https://www.cnblogs.com/annie00/p/5764267.html
Copyright © 2011-2022 走看看