阅读本文大概需要 4 分钟。

原文:http://t.cn/Eau2d0h

译文:http://21cto.com/article/2093

当你意识到你在项目开始时做的轻量、简单的设想竟然完全错了时,你已经用了六个月的时间投入到这个项目上。

现在你需要解决这些问题,才能让这个系统继续运行下去,你发现你用在这个项目上的精力远远超出了你的预期,如果一开始就用正确的方式来做,就不会发生这样的事。

今天,我要告诉你的是一个经常犯的错误,一个会给你带来无穷无尽的问题的单词,那就是“users”。

这个单词有两个最基本的错误:

1、对你的需求来说 “User” 几乎从来都不是一个好的描述。

2、“User” 会导致一个基本的设计安全缺陷。

“user” 的概念是模糊不清的,使用更精准的术语几乎总是能起到更好的效果。

你没有使用者

最开始,没有任何一个软件系统真的有使用者存在。乍一看“user”是一个好的描述,但是你稍微一想就会意识到你的业务逻辑实际上比这要复杂的多。

我会使用三个例子,从一个极端的情况出发。

机票预订系统没有“users”

我曾经给机票预订系统写过访问控制逻辑,下面只是一小部分需求:

  • 旅客可以使用预定记录码通过网站查看预定信息。
  • 购买者可以通过信用卡号后四位数在网站上修改预订信息。
  • 旅行社可以查看和修改他们的预订。
  • 航空公司的值机人员可以根据角色和航空公司来查看和修改预订信息,这需要旅客提供身份信息。
不再一一列举。一些与人类相关的基本概念是“旅客”,“代理”(网站也可是看作代理)和“购买者”。
“user”这个概念根本没用,并且在许多请求中我根本不会使用这个单词,举个例子,我们的请求必须包括旅客和代理人的证件,而不是使用者的证件。

Unix 没有 “users”

我们看一个不太一样的例子。Unix (这些天被称为POSIX)有用户,他们可以登录并执行代码。这样看起来很不错吧?我们深入看一下。
如果我们把所有都当作“users”的话,我们将会有:使用终端或者图形界面登录的人
  • 像邮件或者web服务器这种系统服务也会以“users”的身份运行,例如nginx可以以httpd用户运行。
  • 在服务器上经常会有多人共享一个管理员账号用来SSH登录(例如,亚马逊的Ubuntu虚拟机默认SSH账号就是‘ubuntu’)
  • root 身份,和上面其他身份都不同。
 
上面四个是几乎不同的概念,但是在POSIX上他们都是 “users”. 一会儿我们就会看到,把这些概念都称为‘user’会导致很多安全问题。
在操作上,因为POSIX的用户模型边界存在,我们甚至不能找到一种方式说“只能让 Alice 和 Bob 通过这个账号登录”。

SaaS 服务提供商没有 “users”

Jeremy Green 最近就用户模型在SaaS中的应用在推特上发文,它第一次提醒了我写下这篇文章,他的基本观点是SaaS 服务几乎总是:
1、某个组织中的一个人支付服务费用。
2、一个或多个人共同使用这个服务。
如果你一开始就把这些人作为一个用户,你将会陷入一个痛苦的世界。你无法建立团队模型,你无法组建同时为多人支付的模型,然后你就会开始改造你的系统。现在你在SaaS案例中学到了一课,我们来看一看你的生活。
但是这只是众多例子中的一个:“users”的概念太模糊了。如果你开始怀疑“user”这个词,最终你可能发现最终你其实只需要两个概念:团队(用来组织关系和支付)和成员(实际使用服务的人)。

“Users” 是一个安全问题

“user” 这个单词不仅是业务逻辑的问题,它也导致了一系列安全问题。“user” 这个单词如此的模糊以至于从根本上将两个概念合并了:
  • 一个人。
  • 他们在软件中的代表性。
为了说明这个问题,假设你正在访问一个居心不良的网站,在它服务器上的图片导致了你的浏览器内存溢出。远程网站控制着你的浏览器,并且开始将你的文件上传到他的服务上。为什么它能这样做?
因为浏览器是以系统用户的身份运行的,它被认为与人类身份的你相同,实际上你们是不同的。
你作为’user’,不想上传文件。但是系统的账号也是‘user’,能够上传文件,如果浏览器运行在你的账号之下,他所有的行为会被当作是你的意图,也就是说是你让它这么做的,实际上不是。
这就是被称为Confused Deputy的问题。如果你使用“用户”这个词来描述两个根本不同的东西,那么这个问题就更有可能成为你设计的一部分。

前期设计的价值

花更少的功夫处理相同的问题是成为高产程序员的关键。使用模糊不清的概念比如“用户”来组织你的软件,将会话费大量时间和精力来解决未来发生的问题。一上来就开始编码看起来是高产的,事实恰好相反。
下次你开始一个新的软件项目时,花几个小时预先确定你的术语和概念:你仍然不会完全正确,但你会做得更好。未来的你将感谢你所做的所有预防浪费的工作。

·END·

程序员的成长之路

路虽远,行则必至

本文原发于 同名微信公众号「程序员的成长之路」,回复「1024」你懂得,给个赞呗。

回复 [ 520 ] 领取程序员最佳学习方式

回复 [ 256 ] 查看 Java 程序员成长规划

写代码注意了,打死都不要用 User 这个单词的更多相关文章

  1. jQuery之父:坚持每天都要写代码

    关于作者:John Resig, jQuery之父,同时也是Pro Javascript Techniques和Secrets of the JavaScript Ninja的作者.他目前主持 Kha ...

  2. Delphi/C#之父首次访华:55岁了 每天都写代码

    Delphi.C#之父Anders Hejlsberg 近日首次访华,并在10月24日和27日参加了两场见面会,分享了他目前领导开发的TypeScript项目,并与国内前端开发者近距离交流.本文就为读 ...

  3. Mark一下, dp状态转移方程写对,可是写代码都错,poj 1651 poj 1179

    dp题: 1.写状态转移方程; 2.考虑初始化边界,有意义的赋定值.还没计算的赋边界值: 3.怎么写代码自底向上计算最优值 今天做了几个基础dp,所有是dp方程写对可是初始化以及计算写错 先是poj ...

  4. jQuery 之父:每天写代码

    去年秋天我的支线代码项目 遇到了一些问题,项目进展不足,而且我没法找到一个完成更多代码的方法(在不影响我在Khan Academy方面的工作的前提下). 我主要在周末进行我的支线,当然有时候也在晚上进 ...

  5. [转]<版本一>写代码的小女孩

    天冷极了,下着雪,又快黑了.这是NOIP的前夜.在这又冷又黑的晚上,一个衣衫破烂的小女孩在机房敲着代码.她从班里逃出来的时候还拿着一本算导,但是有什么用呢?那是一本很破旧的书——那么大,一向是她妈妈垫 ...

  6. 使用 .NET WinForm 开发所见即所得的 IDE 开发环境,实现不写代码直接生成应用程序

    直接切入正题,这是我09年到11年左右业余时间编写的项目,最初的想法很简单,做一个能拖拖拽拽就直接生成应用程序的工具,不用写代码,把能想到的业务操作全部封装起来,通过配置的方式把这些业务操作组织起来运 ...

  7. ClownFish:比手写代码还快的通用数据访问层

    http://www.cnblogs.com/fish-li/archive/2012/07/17/ClownFish.html 阅读目录 开始 ClownFish是什么? 比手写代码还快的执行速度 ...

  8. Markdown: 用写代码的思维写文档

    作者:吴香伟 发表于 2014/08/07 版权声明:可以任意转载,转载时务必以超链接形式标明文章原始出处和作者信息以及版权声明 本文不讲解Markdown的语法规则,只关注它带来的好处以及我使用的方 ...

  9. 【腾讯Bugly干货分享】深入理解 ButterKnife,让你的程序学会写代码

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/578753c0c9da73584b025875 0.引子 话说我们做程序员的,都 ...

随机推荐

  1. 如何打造难用,bug多的产品

    本文纯属吐槽,如有雷同,绝非巧合.长期更新,欢迎一起吐槽. 没有产品规划 需求方提出需求后,直接开发,无需经过产品规划,用开发的思维搞出来!于是我们得到了一堆功能的集合.这个集合可以让刚上手的新用户一 ...

  2. Web应急:门罗币恶意挖矿

    门罗币(Monero 或 XMR),它是一个非常注重于隐私.匿名性和不可跟踪的加密数字货币.只需在网页中配置好js脚本,打开网页就可以挖矿,是一种非常简单的挖矿方式,而通过这种恶意挖矿获取数字货币是黑 ...

  3. Salesforce LWC学习(一)Salesforce DX配置

    LWC: Create a Salesforce DX Project and Lightning Web Component:https://www.youtube.com/watch?v=p268 ...

  4. Java高级工程师面试宝典

    Java高级工程师面试宝典 JavaSE 多线程 进程与线程的区别? 答:进程是所有线程的集合,每一个线程是进程中的一条执行路径,线程只是一条执行路径. 为什么要用多线程? 答:提高程序效率 多线程创 ...

  5. Redis缓存数据库基础

    思维导图xmind文件:https://files-cdn.cnblogs.com/files/benjieming/Redis.zip

  6. ES6 Promise对象(七)

    一.Promise介绍1.Promise简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果2.Promise可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函 ...

  7. Vue.js最佳实践--VueRouter的beforeEnter与beforeRouteLeave冲突解决

    用Vue做应用管理系统,通常会在离开某个页面的时候,需要检测用户是否有修改,询问用户需要不需要保存之类的需求 这时候,在读VueRouter文档:组件内的守卫 的时候,发现beforeRouteLea ...

  8. Modern Cpp记录

    #include <iostream> # include <set> #include <chrono> #ifndef UNUSED #define UNUSE ...

  9. .net web mvc 权限验证

    这里分享MVC的权限验证,内容中可能存在一些,莫名其妙的方法,那些是以前封装好的,大致可以根据方法名称知道他的意思. using Game.Entity; using Game.Entity.Plat ...

  10. Centos系统 tomcat 中的应用与北京时间相差8小时

    解决方法: 在 catalina.sh中的 JAVA_OPTS 加上 -Duser.timezone=GMT+08  启动时 startup.sh 会调用 catalina.sh.