我应该将参考透明度做到什么程度?
我正在使用 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.
上面的代码显然不是生产代码 -它纯粹是为了说明目的而编写的。
我不想陷入教条。引用透明代码(如可证明的单元测试)的好处是否证明不太友好的界面是合理的?为了追求参照透明度我应该走多远?
I am building a website using erlang, mnesia, and webmachine. Most of the documentation I have read praises the virtues of having referentially transparent functions.
The problem is, all database access is external state. This means that any method that hits the database is no longer referentially transparent.
Lets say I have a user object in a database and some functions that deal with authentication.
Referentially opaque functions might look like:
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.
Referentially transparency requires that I minimize the amount of referentially opaque code, so the caller must get the object from the database and pass that in as an argument to a function:
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.
The code above is obviously not production code - it is made up purely for illustrative purposes.
I don't want to get sucked into dogma. Do the benefits of referentially transparent code (like provable unit testing) justify the less friendly interface? Just how far should I go in the pursuit of referentially transparancy?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
为什么不完全采用引用透明度呢?
考虑
get_user_from_db
的定义。它如何知道如何与数据库对话?显然它假设了一些(全局)数据库上下文。您可以更改此函数,以便它返回一个将数据库上下文作为其参数的函数。你所拥有的是……这是一个谎言。您无法从用户 ID 转到用户。您还需要其他东西:数据库。
现在只需将其与 userid 进行柯里化,并在稍后给出一个数据库,该函数将为您提供一个用户。当然,在现实世界中,数据库将是句柄或数据库连接对象或其他任何东西。为了进行测试,给它一个模拟数据库。
Why not take referential transparency all the way?
Consider the definition of
get_user_from_db
. How does it know how to talk to the database? Obviously it assumes some (global) database context. You could change this function so that it returns a function that takes the database context as its argument. What you have is...This is a lie. You can't go from a userid to a user. You need something else: a database.
Now just curry that with the userid, and given a Database at some later time, the function will give you a User. Of course, in the real world,
Database
will be a handle or a database connection object or whatever. For testing, give it a mock database.您已经提到了单元测试,请继续用这些术语来思考。您在测试中发现有价值的所有内容都应该是引用透明的,以便您可以对其进行测试。
如果您没有任何可能出错的复杂逻辑,并且单个功能/集成测试就会发现它是正确的,那么为什么还要费劲去额外的距离呢?
想想YAGNI。但真正需要单元可测试性的地方。
You already mentioned unit-testing, keep thinking in those terms. Everything you find value in testing should be refentially transparent so you can test it.
If you don't have any complex logic that could go wrong, and a single functional/integration test would see that it is correct, then why bother going the extra distance?
Think YAGNI. But where unit-testability is a real need.