为什么我经常从头开始实现某些功能

从前有一个Erlang程序员,他需要一个FTP服务器,运行在一个私有网络上的一个主机上。实际上,他不需要一个FTP服务器,他只需要在中央服务器和他的客户端机器之间传输文件,但是他认为他需要一个FTP服务器来完成这个操作。

他在网上搜索了FTP服务器,确实找到了几个。他们当然是免费的,因为即使他工作的组织有很多钱,但是购买这样一种产品的行政程序是相当可观的。这个项目还必须有合适的许可证形式,这样法律部门才会高兴。

他下载了几个这样的服务器,其中一些是无法编译的,即使它们确实编译了,它们也必须正确配置才能运行,这并不容易。

突然,我们的程序员有了一种想法:他可能可以自己编写一个FTP服务器,而自己编写FTP服务器可能比查找和安装其他人编写的FTP服务器要快。

他问自己:“我想做什么呢?”。

“将远程目录的文件列出来,在本地和远程机器之间拷贝文件等等。”

然后他想起他正在做的项目使用了分布式Erlang。

他想:“这一定很容易”。他是对的。

然后…在服务器机器上,他输入了如下命令:

1
2
3
>$erl -name server -cookie ASDRTFERT
1> node().
'server@host1.somenet.com'

然后他在另一台机器上输入如下命令:

1
2
3
>$erl -name client1 -cookie ASDRTFERT
1> node().
'client1@host23.somenet.com'

现在他已经启动了两个Erlang节点。分布式Erlang的优点是你可以轻松地在任何节点上运行代码,因此要检查他是否能够从客户机节点访问服务器节点,程序员就会输入如下命令:

1
2
3
2> rpc:call(server@host1.somenet.com',
erlang, node, []).
'server@host1.somenet.com'

如果命令在第一台机器上发出,那将会发生什么。我们可以自己尝试一下。现在我们的程序员知道他可以就像在本地机器上一样调用远程机器上的任何功能。

例子如下:

如果本地命令是:

1
> file:get_cwd()

在服务器上执行这个命令时,他只需要调用:

1
> rpc:call(server@host1.somenet.com',file, get_cwd, []).

那么列出远程机器的文件,他输入如下命令即可:

1
2
3
4
5
1> rpc:call(server@host1.somenet.com',
file, list_dir, ["."]).
{ok, ["Makefile",
"readme",
....

然后他决定把远程机器的Makefile文件拷贝到他本地机器上,因此他写了如下命令:

1
2
3
4
5
2> {ok, Bin} = rpc:call(server@host1.smenet.com',
file, read_file, ["Makefile"]).
<<".SUFFIXES: .erl .beam .yrl" .....>>
3> file:write_file("Makefile", [Bin]).
ok

此时,所有在shell中键入的内容变得冗长乏味,因此他启动了emacs并编写了如下代码:

1
2
3
4
5
6
7
-module(myftp).
-export([get_file/1]).

get_file(F) ->
{ok, B} = rpc:call(server@host1.smenet.com',
file, read_file, [F]),
file:write_file(F ++ ".copy", [B]).

然后他编译并测试他的程序:

1
2
3
4
4> c(myftp).
{ok,myftp}
5> myftp:get_file("Makefile").
ok

就这么简单,他搞定了。

小小的总结

如果你有合适的工具,那么在从头开始实现一些东西比很麻烦地下载编译和安装别人写的东西更快。

这是一个真实的故事,只不过我刚刚写了这段代码。编写此代码和博客的时间与在我的机器上找到并安装一个FTP服务器差不多。

原文链接: [http://armstrongonsoftware.blogspot.com/2006/09/why-i-often-implement-things-from.html]