记一次C#代码审查

简介:

记一次C#代码审查


你想在这里实现什么?

有什么要求?

这是启动每个代码审查过程的最佳方式。一要求做代码审查的人已经知道这些问题的答案。 此函数返回一个 GitHub 收藏的用户列表。 在 GitHub 上,有一个追踪用户的能力。

我曾为一个朋友做过一个简单的代码审查(备注:下面是 C# 代码)

 
  1. public IEnumerable < GitHubUser > FavoritesList() { 
  2.  
  3.  
  4.  CookieHelper cookieHelper = new CookieHelper(this.HttpContext); 
  5.  
  6.  
  7.  HttpCookie httpCookie = cookieHelper.SetAndGetHttpCookies(); 
  8.  
  9.  
  10.  MyCookie myCookie = new MyCookie() { 
  11.  
  12.  
  13.   ID = Convert.ToInt32(httpCookie["Id"]) 
  14.  
  15.  
  16.  }; 
  17.  
  18.  
  19.  List < GitUser > favoritesList = new List < GitUser > (); 
  20.  
  21.  
  22.  using(var db = new GitHubContext()) { 
  23.  
  24.  
  25.   var results = (from ch in db.CookiesHistory where ch.UserId == myCookie.ID select new { 
  26.  
  27.  
  28.    GitUserId = ch.GitUserId 
  29.  
  30.  
  31.   }); 
  32.  
  33.  
  34.   foreach(var result in results) { 
  35.  
  36.  
  37.    var user = (from u in db.GitUsers where u.Id == result.GitUserId select new { 
  38.  
  39.  
  40.     u 
  41.  
  42.  
  43.    }).First(); 
  44.  
  45.  
  46.    favoritesList.Add(user.u); 
  47.  
  48.  
  49.   } 
  50.  
  51.  
  52.  } 
  53.  
  54.  
  55.  return favoritesList; 
  56.  
  57.  

看起来是很普通的代码。从哪儿开始呢? 上下文! 上下文是重点。这很明显。但首先,你需要提出以下问题:

- 你想在这里实现什么?

- 有什么要求?

这是启动每个代码审查过程的最佳方式。一要求做代码审查的人已经知道这些问题的答案。 此函数返回一个 GitHub 收藏的用户列表。 在 GitHub 上,有一个追踪用户的能力。

初步意见:

- 我看到 Git,但没有GitHub API客户端调用。

- LINQ 表示我们正在做一些查询。

- Context 关键字是实体框架(ORM 访问数据)。

- HttpContext 和 Cookies 在 ASP.NET 范围内执行。

- 没有参数的函数返回收藏夹列表。

问题:

- 在哪里调用 GitHub API? 这是一个存储在外部数据存储区中的 GitHub 数据的快照。

命名约定

理想的代码是易于理解的代码。我确实偏爱 KISS 的原则; 这是一个务实的做法。 一个简单而优雅的代码胜利一切。 我希望读一份代码就像读一本叙述书。 现实中一定也存在某种机制,可以使我们的代码更好读。让我们从函数名开始。

 
  1. public IEnumerable<GitHubUser> FavoritesList() 

这还不够。它没有告诉我任何信息。

 
  1. public IEnumerable<GitHubUser> FavouriteGitHubUsers() 

好点了……不过 GitHub 上并没有 favorites 的概念。只有一个 followed users 的概念。

 
  1. public IEnumerable<GitHubUser> FollowedGitHubUsers() 

正确的命名函数并把它作为商务语言的简单解释是很重要滴。 领域驱动设计专家可能会称之”通俗易懂“的沟通。

“收藏”这个词会使混迹 GitHub 的老鸟把它和其他东西混淆。这种混淆会造成时间的浪费,换言之,就是浪费金钱。不要去创造新的说法,当你需要“引入”新词或新说法时,多讨论下,问问该领域的专家和小伙伴们。

或许已经有一个适合该函数的名称或者些许代码。像我们号召的一样,力求创造简短的代码,我们还应该保证我们领域词汇的统一,简洁,以及通俗易懂。

无参的函数

对我来说,没有参数的函数是一个反面模式。这可能在某些情况下有用,但这些情况非常罕见,主要与已经不完整的设计架构有关。

如果函数没有任何参数,那么它有什么作用呢? 它从哪里获得输入和当前状态呢? 它可能是一个全局的 - 但这也是一个反面模式。函数需要纯输入和纯输出。

纯函数是一个很好的概念; 这是我在探索函数式编程时学到的。

纯函数是一个这样的函数:其中返回值仅由其输入值确定,而没有其他可观察到的副作用。这是在数学中的函数如何工作的原理。对于相同的 x 值,Math.cos(x)将始终返回相同的结果。

由于 cookie 中的全局状态和对 HTTPContext 的依赖,当前函数不是纯函数。我朋友曾尝试将该逻辑隐藏在 CookieHelper 中来访问它们,但这还不够。 问题依然存在。

在 Asp.NET 中,在函数之外使用 HTTPContext。它不应该泄漏到里面。当前代码不能在不同的上下文中工作。如果我们在没有全局的 HTTPContext 的进程中执行它,它将崩溃。

这里还有另一个反模式,新的关键字。尝试注入尽可能多的东西。 这个建议可能被不正确地使用,但依赖仍不容忽视。

仔细看看代码,其中包含 CookieHelper 允许访问 myCookie.ID 的逻辑。 我们可以通过引入一个包含参数 ID 的函数来从这个函数中移除所有这些逻辑。

 
  1. public IEnumerable<GitHubUser> FollowedGitHubUsers(int cookieId) 

我们不在乎 cookieId 的值来自哪里。这给出了更多的选择,因为我们可以从其他源获取 cookieId,而不仅仅是从 cookie 中。

更改后的代码

 
  1. public IEnumerable < GitHubUser > FollowedGitHubUsers(int userId) { 
  2.  
  3.  
  4.  List < GitHubUser > favoritesList = new List < GitHubUser > (); 
  5.  
  6.  
  7.  using(var db = new GitHubContext()) { 
  8.  
  9.  
  10.   var results = (from ch in db.CookiesHistory where ch.UserId == userId select new { 
  11.  
  12.  
  13.    GitUserId = ch.GitUserId 
  14.  
  15.  
  16.   }); 
  17.  
  18.  
  19.   foreach(var result in results) { 
  20.  
  21.  
  22.    var user = (from u in db.GitUsers where u.Id == result.GitUserId select new { 
  23.  
  24.  
  25.     u 
  26.  
  27.  
  28.    }).First(); 
  29.  
  30.  
  31.    favoritesList.Add(user.u); 
  32.  
  33.  
  34.   } 
  35.  
  36.  
  37.  } 
  38.  
  39.  
  40.  return favoritesList; 
  41.  
  42.  

代码变得清晰并且我不再需要担心 Cookie。

将代码划分为独立的功能

有两个 DB 查询,都使用同样的 Context。 有如下代码:

 
  1. public IEnumerable < GitHubUser > FollowedGitHubUsers(int userId) { 
  2.  
  3.  using(var db = new GitHubContext()) { 
  4.  
  5.   var followedUserIds = this.GiveMeFollowedUsersIdFor(db, userId); 
  6.  
  7.   return this.FindUsers(db, followedUsersIds); 
  8.  
  9.  } 
  10.  

代码是不是看起来既简单又美观? 所有这一切,归功于功能的提取,使得代码非常容易阅读。在这个层次上,我不在乎如何获得用户。 我只需要专注一些功能和输入的编排。

如果我需要了解更多的细节,我才会进入这个方法查看。

 
  1. private IEnumerable<GitHubUser>FindUsers(GitHubContext db, IEnumerable<int> userIds) 
  2.  
  3.  
  4.  
  5.  
  6.         List<GitHubUser> favoritesList = new List<GitHubUser>(); 
  7.  
  8.  
  9.         foreach (var result in results) 
  10.  
  11.  
  12.         { 
  13.  
  14.  
  15.             var user = (from u in db.GitUsers 
  16.  
  17.  
  18.                         where u.Id == result.GitUserId 
  19.  
  20.  
  21.                         select new { u }).First(); 
  22.  
  23.  
  24.             favoritesList.Add(user.u); 
  25.  
  26.  
  27.         } 
  28.  
  29.  
  30.     } 
  31.  
  32.  
  33.     return favoritesList; 
  34.  
  35.  

运用这个函数也让我能更好地理解它。这里的输入和输出非常明确。简单、短小的函数可以更加清晰地帮助大脑消化信息。而使用较小的函数,我们必须考虑代码行数量较少的情况。

拥有明确的输入和输出,我们就可以界定范围和上下文。 这里没有 cookie helper。我们不用担心从哪里获取 userId 的问题。我们避开它的复杂性,而把精力放在重要的问题上。 这样能有效避免函数中的干扰项。


作者:OSC-协作翻译

来源:51CTO

相关文章
|
1月前
|
监控 算法 安全
深入白盒测试:静态分析与代码质量保障
【4月更文挑战第2天】 在软件测试的众多技术中,白盒测试以其对内部结构和逻辑的透明性而著称。本文旨在探讨白盒测试中的一项关键技术—静态分析,它如何帮助我们确保代码的质量,以及它在现代软件开发周期中的重要性。通过深入分析静态分析工具的使用和结果解读,我们揭示了这一技术如何提高代码的健壮性和可靠性,减少运行时错误,并优化性能。文章还将讨论将静态分析集成到持续集成/持续部署(CI/CD)流程中的最佳实践,以及如何有效地利用反馈来改进代码质量。
18 1
|
3月前
|
程序员
提高代码质量的五个技巧
【2月更文挑战第2天】写出高质量的代码是每个程序员的追求,但是实现这一目标并不容易。本文将介绍五个技巧,帮助你提高代码的质量。
|
5月前
|
前端开发 JavaScript 持续交付
前端代码审查规范
前端代码审查规范
|
11月前
|
XML 安全 Linux
C++代码审查工具Cppcheck和TscanCode
C++代码审查工具Cppcheck和TscanCode
|
运维 Java 测试技术
重构性项目如何回归测试?
重构性项目如何回归测试?
|
IDE Java 程序员
|
开发者
聊聊软件开发的代码审查
聊聊软件开发的代码审查
聊聊软件开发的代码审查
|
自然语言处理 监控 安全
如何提高代码质量
说起代码质量,脑子里会冒出很多词,命名规范、格式规范、日志规范、单元测试覆盖率... 但我觉得,代码质量总结起来就两个:好看和好用。 好看是指代码可读性好,容易理解、容易维护,别人接手了不骂你;好用则指代码健壮,不容易出错,机器跑着不骂你。即使出错,也容易定位,容易止损和恢复。
|
程序员 API
如何提高代码质量?
本文从 产品,接口,指标,日志,代码清晰度,代码复杂度 等方面,谈谈如何提高代码质量。
3937 0

热门文章

最新文章

相关实验场景

更多