当你意识到你在项目开始时做的轻量、简单的设想竟然完全错了时,你已经用了六个月的时间投入到这个项目上。现在你需要解决这些问题,才能让这个系统继续运行下去,你发现你用在这个项目上的精力远远超出了你的预期,如果一开始就用正确的方式来做,就不会发生这样的事。

今天,我要告诉你的是一个经常犯的错误,一个会给你带来无穷无尽的问题的单词,那就是“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的问题。如果你使用“用户”这个词来描述两个根本不同的东西,那么这个问题就更有可能成为你设计的一部分。

前期设计的价值

花更少的功夫处理相同的问题是成为高产程序员的关键。使用模糊不清的概念比如“用户”来组织你的软件,将会话费大量时间和精力来解决未来发生的问题。一上来就开始编码看起来是高产的,事实恰好相反。

下次你开始一个新的软件项目时,花几个小时预先确定你的术语和概念:你仍然不会完全正确,但你会做得更好。未来的你将感谢你所做的所有预防浪费的工作。

扩展阅读

这70个Java必背英语单词不会,就别说你是Java程序员!

数据库连接池DBCP的使用

一个老程序员的忠告:千万不要一辈子靠技术生存

一行代码完成Java的Excel读写

MySQL 在并发场景下的问题及解决思路

作者:21CTO社区

来源:http://21cto.com/article/2093

永远不要在代码中使用“User”这个单词的更多相关文章

  1. 在VS代码中使用版本控制

    在VS代码中使用版本控制 Visual Studio Code集成了源代码控制,并包含了内置的Git支持.许多其他源代码控制提供程序可通过VS Code Marketplace上的扩展获得. Git历 ...

  2. [转]如何在 JS 代码中消灭 for 循环

    一,用好 filter,map,和其它 ES6 新增的高阶遍历函数 二,理解和熟练使用 reduce 三,用递归代替循环(可以break!) 四,使用高阶函数遍历数组时可能遇到的陷阱 五,死磕到底,T ...

  3. Java基础学习总结(81)——如何尽可能的减少Java代码中bug

    Java编程语言的人气自然无需质疑,从Web应用到Android应用,这款语言已经被广泛用于开发各类应用及代码中的复杂功能. 不过在编写代码时,bug永远是困扰每一位从业者的头号难题.在今天的文章中, ...

  4. Python-Jenkins API使用 —— 在后端代码中操控Jenkins

    最近在工作中需要用到在后台代码中触发Jenkins任务的构建,于是想到Jenkins是否有一些已经封装好的API类库提供,用于处理跟Jenkins相关的操作.下面就简单介绍下我的发现. Linux C ...

  5. 在C#代码中应用Log4Net系列教程(附源代码)

    Log4Net应该可以说是DotNet中最流行的开源日志组件了.以前需要苦逼写的日志类,在Log4Net中简单地配置一下就搞定了.没用过Log4Net,真心不知道原来日志组件也可以做得这么灵活,当然这 ...

  6. “RazorEngine.Templating.TemplateCompilationException”类型的异常在 RazorEngine.NET4.0.dll 中发生,但未在用户代码中进行处理

    错误信息: "RazorEngine.Templating.TemplateCompilationException"类型的异常在 RazorEngine.NET4.0.dll 中 ...

  7. C#代码中实现两个表(DataTable)的关联查询(JOIN)

    之前通常都是使用SQL直接从数据库中取出表1和表2关联查询后的数据,只需要用一个JOIN就可以了,非常方便.近日遇到一种情况,两个表中的数据已经取到代码中,需要在代码中将这两个表关联起来,并得到它们横 ...

  8. 【转】代码中特殊的注释技术——TODO、FIXME和XXX的用处

    (转自:http://blog.csdn.net/reille/article/details/7161942) 作者:reille 本博客网址:http://blog.csdn.net/reille ...

  9. 在C#代码中应用Log4Net(二)典型的使用方式

    不管用什么框架,学什么东西,最初的想法还不是尽快地用上这个框架,所以我们在这个章节还是不打算介绍具体配置节的应用,而是直接给出一个经典的使用样例,让你尽快上手.即使你对Log4Net的配置不熟悉也完全 ...

随机推荐

  1. c++线性表和数组的区别

    在传统C语言程序中,描述顺序表的存储表示有两种方式:静态方式.动态方式 顺序表的静态存储表示: #define maxSize 100 typedefintT; typedefstruct{ T da ...

  2. 华为云配置Objected-based Storage System

    本实验要求基于开源的对象文件系统(例如Ceph),搭建视频点播(VoD)网站.可参考使用Ceph, wordpress, php 以及nginx 实现相关功能,主要包含以下方面: 配置Ceph; 配置 ...

  3. 区块链入门到实战(23)之以太坊(Ethereum) – 虚拟机架构

    以太坊(Ethereum)网络中,定义了一组通用协议用于支持智能合约的运行,其核心便是以太坊(Ethereum)虚拟机. 下图解释了该架构: 开发人员使用Solidity等开发语言开发智能合约 源程序 ...

  4. php 正则表达式匹配(持续更新)

    正则表达式匹配网址: <?php header('Content-type:text/html;charset=utf-8'); $str = ' 百度http://www.baidu.com网 ...

  5. 远程调试在Linux车机中的应用

    导读 在软件开发过程中,调试是必不可少的环节,嵌入式操作系统的调试与桌面操作系统的调试相比有很大差别,嵌入式系统的可视化调试能力比桌面操作系统要弱一点.对于导航这种业务场景比较复杂的程序开发,可视化调 ...

  6. 创建VUE+Element-UI项目

    创建项目步骤 安装node.js后,使用管理员角色在cmd中依次运行下列步骤 vue init webpack hello-vue 创建项目文件 cd hello-vue 进入项目 npm insta ...

  7. json对象遍历顺序问题

    对json对象遍历我们一般使用for in循环,或者Object.keys + 数组方法.在接触js以来听到过一种说法: for in 遍历顺序是不可靠的 但是在实际开发中for in 循环也是按照其 ...

  8. 【Android】Android开发初学者实现拨打电话的功能,拨打电话app小demo实现

    作者:程序员小冰,GitHub主页:https://github.com/QQ986945193 新浪微博:http://weibo.com/mcxiaobing 首先先给大家看一下最终实现的效果: ...

  9. Java拷贝——深拷贝与浅拷贝

    深拷贝和浅拷贝 值类型 vs 引用类型 在Java中,像数组.类Class.枚举Enum.Integer包装类等等,就是典型的引用类型,所以操作时一般来说采用的也是引用传递的方式: 但是Java的语言 ...

  10. 如何解读 Java IO、NIO 中的同步阻塞与同步非阻塞?

    原文链接:如何解读 Java IO.NIO 中的同步阻塞与同步非阻塞? 一.前言 最近刚读完一本书:<Netty.Zookeeper.Redis 并发实战>,个人觉得 Netty 部分是写 ...