Tony Han

Happy hacking

Page 2


How does Plug.Builder work?

(本文涉及的源码需要有一些对macro的了解才比较容易看懂)

上回说到,我们可以利用Plug,搭配Cowboy这个web server来写一个简单的web app。而实际中我们不可能把所有的处理逻辑都放在一个Plug中,代码既不容易维护,也不能重复利用Plug。

正如Plug的名字(插头)一样,我们可以把一个个的Plug连起来,组成一个功能强大的Plug pipeline。就像你到国外旅行,电源适配器接口不对应,就可以买个转换器(其实就是一个插头),一头插着你的电源,另一头插在酒店的插座上。 再比如Plug实现了Plug.Logger,把它“插在”在你的整个Plug的pipeline中,就帮你加入了日志的功能。

Plug.Builder的目的就是为了让你方便地写出Plug pipeline,我们还是先来看文档里的例子? :D

defmodule MyApp do
  use Plug.Builder

  plug Plug.Logger
  plug :hello, upper: true

  def hello(conn, opts) do
    body = if opts[:upper], do: "WORLD", else: "world"
    send_resp(conn, 200, body)
  end
end

MyApp就是一个组合了几个Plug的Plug pipeline,按顺序有Plug.Loggerhellosend_resp是从Conn引入的,plug这个macro显然是从Plug.Builder引入的,那具体是如何引入,以及为什么这样就可以定义一个Plug pipeline,秘密都在use Plug.Builder这行代码中。

 Define plugs one by one

当以一个Module为参数调用了use这个macro(是的,use也是一个macro)时,其实最终只是调用了那个Module的__use__ macro而已。是的,还是macro ╮(╯▽╰)╭

我们来看Plug.Builder的__use_...

Continue reading →


Should we do what users need or what we require them to need?

到底我们应该做用户需要的东西,还是要做我们要求用户需要的东西?

看这个句式,很显然,我的观点是后者。因为对于这个句式,作者自己的观点都是后边那个。

我们常常说,一个好的产品要满足用户的需求。这句话说的没错,一个连用户需求都满足不了的产品,不管做的好不好,一定活不下去,一个活不下去的产品也不能算是一个好的产品。所以你看小米,人家现在活得多滋润,就是因为人家抓住了用户的需求,并且极大地满足了用户需求,确实是一个好产品。

当然,我不是小米的粉,讲小米只是为了铺垫一下。(好像谁都看得出来)

如果目标只是定在了“好”产品这一级,那苹果现在也不会这么牛了。当年诺基亚也挺牛的,满世界都是它新品的广告牌,N 系列的拿出去,又实用,又漂亮,又能满足用户装逼的需求,当锤子使也挺好用的。而现在,不也就做着做着就做死了么。就是因为有一群坚信“用户根本不知道自己需要什么”的人觉得,用户要什么我就给什么,太没意思的,一点都满足不了我的控制欲,而且他们相信自己比用户有更高的品味、更好的审美,以及更加确定的相信什么才是更美的、人们更加需要的,他们不想只是遵守游戏规则,而是想要自己制定游戏规则。所以才有了进步。

本文的主角也不是苹果,苹果在这里也只是一个论据。另一个论据是 [stackoverflow.com](stackoverflow.com) ,还更像是本文的主角。

我自认为自己,像大多数自以为是的程序员一样,坚信自己有独特的品味、不凡的追求。写文字必须是 Markdown ,Word 是什么,好像没听过,可能是来自远古的东西吧。只用 Google,把 baidu 当做 ping 的web版,哪怕要“跨过山和大海”。看的书、用的系统、甚至出来“混”的名号,都必须是英文的,即便我们和外国人讲英文除了寒暄几句就不知道讲什么了。但当我从开始一点点用 stackoverflow 之后,还是有一种被雷击中的感觉。

stackoverflow 是一个技术的问答社区,里边有对于各种基本乃至更高级问题的各种答案,有谁说过离了它可能都没办法写代码了。在 stackoverflow...

Continue reading →


How does Plug work with Cowboy?

Plug的文档里有个通过Plug写应用程序的简单例子:

defmodule MyPlug do
  import Plug.Conn

  def init(options) do
    # initialize options

    options
  end

  def call(conn, _opts) do
    conn
    |> put_resp_content_type("text/plain")
    |> send_resp(200, "Hello world")
  end
end
# Run the server
$ iex -S mix
iex> c "path/to/file.ex"
[MyPlug]
iex> {:ok, _} = Plug.Adapters.Cowboy.http MyPlug, []
{:ok, #PID<...>}

本文就来简单聊一下这寥寥几行代码是如何起作用的。

让我们从最后看起,Cowboy是Erlang写的一个Small, fast, modular HTTP server,有点类似于ruby里的thin的角色。Plug则实现了Cowboy的Adapter,使我们可以方便的写出一个web app。

Plug.Adapters.Cowboy.http MyPlug, [],其实Cowboy只是拼装了一些参数,并用它来调:cowboystart_http函数。最后拼好的这些参数是:

[MyPlug.HTTP,                # ref
100,                         # default value for acceptors
[port: 4000],                # default value for options
[env: [
  dispatch: :cowboy_router.compile(dispatches), # important!
  compress: false],          # default
...

Continue reading →