我正在使用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.
上面的代码显然不是生产代码 - 它纯粹是出于说明目的而构成的。
我不想陷入教条。引用透明代码(如可证明的单元测试)的好处是否证明了不太友好的接口?我应该在追求传教的过程中走多远?
答案 0 :(得分:9)
为什么不一直采用参考透明度?
考虑get_user_from_db
的定义。它如何知道如何与数据库通信?显然,它假设一些(全局)数据库上下文。您可以更改此函数,以便它返回一个以数据库上下文作为参数的函数。你拥有的是......
get_user_from_db :: userid -> User
这是谎言。您无法从用户标识转到用户。你需要别的东西:数据库。
get_user_from_db :: userid -> Database -> User
现在只需使用用户标识来解决这个问题,并在以后给出一个数据库,该函数将为您提供一个用户。当然,在现实世界中,Database
将是句柄或数据库连接对象或其他任何东西。为了测试,给它一个模拟数据库。
答案 1 :(得分:3)
您已经提到了单元测试,请继续思考这些术语。您在测试中发现的所有内容都应该是可靠的,因此您可以对其进行测试。
如果您没有任何可能出错的复杂逻辑,并且单个功能/集成测试会发现它是正确的,那么为什么还要花费额外的距离呢?
思考YAGNI。但是,单位可测性是一个真正需要的地方。