我应该在多大程度上采用参考透明度?

时间:2009-11-20 17:35:57

标签: functional-programming erlang mnesia

我正在使用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.

上面的代码显然不是生产代码 - 它纯粹是出于说明目的而构成的。

我不想陷入教条。引用透明代码(如可证明的单元测试)的好处是否证明了不太友好的接口?我应该在追求传教的过程中走多远?

2 个答案:

答案 0 :(得分:9)

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

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

get_user_from_db :: userid -> User

这是谎言。您无法从用户标识转到用户。你需要别的东西:数据库。

get_user_from_db :: userid -> Database -> User

现在只需使用用户标识来解决这个问题,并在以后给出一个数据库,该函数将为您提供一个用户。当然,在现实世界中,Database将是句柄或数据库连接对象或其他任何东西。为了测试,给它一个模拟数据库。

答案 1 :(得分:3)

您已经提到了单元测试,请继续思考这些术语。您在测试中发现的所有内容都应该是可靠的,因此您可以对其进行测试。

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

思考YAGNI。但是,单位可测性是一个真正需要的地方。