当前位置:   article > 正文

程序员的上帝视角(3)-纯粹_上帝程序员 人性 源代码

上帝程序员 人性 源代码

方法/函数,是编程中最常见的概念。我们几乎对其已经熟悉到不能再熟悉了。但是,由于承载了大部分的业务逻辑,大多数的bug都出现在的方法体/函数体的定义中。

我们先看如下实例代码:

  1. // 根据权限过滤相册,并返回具有权限的相册列表
  2. public List<Album> filterByPermission(String loginPersonId, List<Album> albums) {
  3. // 如果相册列表的第一个所有者是当前用户,那么直接返回整个列表
  4. if (loginPersonId == albums.get(0).getPersonId()) {
  5. return albums;
  6. }
  7. List<Album> newAlbums = new ArrayList<Album>();
  8. ...
  9. ...
  10. return newAlbums;
  11. }

上面这段代码,从方法名上可以看到是根据某个用户的ID来过滤要访问的相册列表。就像你访问他人的QQ相册一样。如果目标对象有10个相册,如果当前用户是作者,自然可以访问所有相册;如果你是对方好友,可能只能访问其中的8个,如果只是游客,可能只能访问公开的1个相册。该方法就是用来完成过滤功能的。

第一句,personId == albums[0],那么,登录用户就是相册的作者。相册作者当然拥有所有相册的权限,所以返回原始的相册。这里就有一个假设,所有相册的personId完全相同。这就属于产品场景代入感太强,而忽略了方法本身所含有的意义。这样写,至少会带来以下方面的隐患:

1. 重用隐患。其他人调用这个方法,会出现错误,因为从方法名,看不出你的业务意义会有隐含的意义。换句话说,这个方法使用了很通用的方法名,却有不少隐含的业务限制在里面。暴露出去就是很大的问题。

2.安全隐患。有人把自己拥有的相册ID追加到最前面,而将很多其他的相册ID追加到后面。那么会产生什么样的效果呢?利用第一个相册(自己的)进行判断,结果为true,直接返回所有,相当于拥有了所有相册的权限。唯一还能正常工作的场景,可能就是调用者自己增加了这方面的校验和限制。

这属于典型的业务场景带入太深——假定该方法被调用到时,一定是进入单个人的相册空间。对于列表中的每个相册均进行判断才是正确的写法,修改后的代码可以写作:

  1. public List<Album> filterByPermission(String loginPersonId, Album[] albums) {
  2. List<Album> newAlbums = new ArrayList<Album>();
  3. for album in albums {
  4. if album.getPersonId() == loginPersonId || hasPermission(loginPersonId, album) {
  5. newAlbums.add(album);
  6. }
  7. }
  8. return newAlbums;
  9. }

修复完bug并不是目的。我们真正要探究的是,思想深处为什么会产生这样的想法。为何会将业务场景过多带入到代码实现中?如果程序员在编写代码时,只将albums参数当做相册列表来看待,而不做过多业务假设,便不会写出如此脆弱的代码。

思索良久,我得出了“纯粹”两个字。参数是纯粹的,参数中所蕴含的意义,仅仅与其数据结构/数据类型相关。一旦脱离“纯粹”二字,便容易让我们有各种假设,导致只有在特定场景下才正确的代码。

我们再来看一段代码:

  1. public boolean checkArticleDeletedStatusByTitle(String title) {
  2. List<Article> articles = this.queryByTile(title)
  3. if articles.size() == 0 {
  4. return true;
  5. }
  6. if (articles[0].getStatus() == DELETED) {
  7. return true;
  8. }
  9. ... 其他逻辑
  10. }

该方法首先根据标题,查找文章列表。然后,获得文章列表的第一篇文章,并判断第一篇文章的状态是否为删除。

当问到为什么会有这样的逻辑时,同事告诉我,因为queryByTitile()方法,已经在数据库中按照【状态】字段进行了倒序排序。而状态值——DELETED,如果存在,一定是最大值。

这其实假定了以后不会新增新的状态值,但万一新增状态,即使没有改动到该代码逻辑,但是该代码却引发了bug。

我们可以得出结论,这是针对this.queryByTile()方法的返回值,带入了特定场景。而并未将其当做单纯的List<Artticle>来看待。这是针对返回值,为按照“纯粹”的规则进行看待。

问题很简单,修复问题也很简单。但这完全是意识问题。我想,如果用“纯粹”来抽象方法的“参数”和“返回值”应该是比较恰当的。当我们进行逻辑编写时,无论是参数,还是调用其他方法的返回值,从“纯粹”的角度来看待它们,不带入任何业务场景。看待问题的角度和思考问题的思路,是否会有不同呢?

欢迎评论区讨论!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/520375
推荐阅读
相关标签
  

闽ICP备14008679号