9

我正在使用 erlang、mnesia 和 webmachine 构建一个网站。我读过的大多数文档都赞扬了具有引用透明功能的优点。

问题是,所有数据库访问都是外部状态。这意味着访问数据库的任何方法都不再是引用透明的。

假设我在数据库中有一个用户对象和一些处理身份验证的函数。

引用不透明函数可能如下所示:

handle_web_request(http_info) ->
  is_authorized_user(http_info.userid),
  ...
%referentially opaque
is_authorized_user(userid) ->
  User = get_user_from_db(userid),
  User.is_authorized.

%referentially opaque
lots_of_other_functions(that_are_similar) ->
  db_access(),
  foo.

引用透明性要求我尽量减少引用不透明代码的数量,因此调用者必须从数据库中获取对象并将其作为参数传递给函数:

handle_web_request(http_info) ->
  User = get_user(http_info.userid),
  is_authorized_user(User),
  ...

%referentially opaque
get_user(userid) ->
  get_user_from_db(userid).

%referentially transparent      
is_authorized(userobj) ->
  userobj.is_authorized.

%referentially transparent    
lots_of_other_functions(that_are_similar) ->
  foo.

上面的代码显然不是生产代码 - 它纯粹是为了说明目的而组成的。

我不想陷入教条。引用透明代码(如可证明的单元测试)的好处是否证明了不太友好的界面?在追求参照透明方面我应该走多远?

4

2 回答 2

9

为什么不一直采用参考透明度呢?

考虑 的定义get_user_from_db。它如何知道如何与数据库对话?显然,它假设了一些(全局)数据库上下文。您可以更改此函数,使其返回一个将数据库上下文作为其参数的函数。你所拥有的是...

get_user_from_db :: userid -> User

这是个谎言。您不能从用户 ID 转到用户。你需要别的东西:一个数据库。

get_user_from_db :: userid -> Database -> User

现在只需使用 userid 进行curry,并在稍后给定一个数据库,该函数将为您提供一个用户。当然,在现实世界中,Database将是句柄或数据库连接对象或其他任何东西。为了测试,给它一个模拟数据库。

于 2009-11-21T00:54:54.567 回答
3

您已经提到了单元测试,请继续以这些术语思考。您在测试中发现的所有价值都应该是参考透明的,以便您可以对其进行测试。

如果您没有任何可能出错的复杂逻辑,并且单个功能/集成测试会发现它是正确的,那么为什么还要费心去额外的距离呢?

想想雅格尼。但是单元可测试性是真正需要的地方。

于 2009-11-20T22:36:47.263 回答