dotNET Core:编码规范

在项目开发过程中,由于时间紧、任务重,很容易导致面向功能编程。实现相同的功能,代码可以写的很优雅,也可以写的很晦涩和复杂。现在的工作,都需要进行团队协作,代码就需要有一定的规范进行指引,因为我们需要写出让人可以轻易读懂的代码,而不仅仅是机器。

规范没有绝对的标准,遵循大部分人都认可的一种方式就可以了,保持统一。比如在 dotNET Core 中,我们可以参考下 dotNET Core 的源码,最终制定一个适合团队的规范即可。

下面是我理解的正确的一些规范:

基本准则

1、命名的规范分为两种:Pascal(大驼峰)和驼峰(小驼峰),示例如下:

• Pascal:UserName
• 驼峰:userName

2、命名要有意义,需要看到名称知其含义。少用拼音和匈牙利命名法。

示例
Int price=20;
UserInfo userInfo=GetUserInfo(userId);
Int p=20;×
Int intPrice=20;×

3、对于类的成员变量,用this关键字,增强代码可读性。
4、对于基类的成员变量,用base关键字,增强代码可读性。

名称规范

好的名称可以让我们减少很多不必要的注释,可以让代码阅读者很容易就理解代码的意思。但命名不是一件容易的事情,在命名的时候,通常伴随着我们对代码逻辑的思考。比如:如果你不能给一个函数很准确地命名,那可能这个函数的职责不单一,做的事情太多,才导致一个名称很难概括,意味着代码可能需要重构。好的命名是我们写好代码的基础。

命名空间

命名空间采用Pascal命名法:

namespace Fw.Application{}
namespace Fw.SmartFlow.Acitivity{}

实际工作中,我们会将很多逻辑上属于同一类的文件,在物理上分成不同的目录,这时建议修改命名空间为相同的命名空间。

类采用Pascal命名法:

public class UserService{}

类是对属性和方法的封装,类有很多的种类:

  • 跟数据库表对应的实体类

  • 处理业务逻辑的业务类

  • 提供扩展方法的扩展类

  • 接口层的数据传输类

不同的种类可以约定俗成地进行一些名称的约束,比如扩展类用 Extension 结尾、接口层的使用 Request、Response 结尾,等等,这样在阅读代码时就知道什么类的职责是什么。

接口

接口采用大写I+Pascal命名法:

public interface IUserService{}

方法

方法采用Passcal命名法:

public string GetUserName(){}

方法的命名需要比较具体,越抽象的名称越难以理解。例如,InitData() 就是一个不太好的名称,改成 InitConfiginfo() 会更好些。另外,方法的命名在同一类型的语义下要保持一致,在一些项目中看到查找类的方法,有 GetXXX、QueryXXX、FindXXX 等等。五花八门的方式会提升阅读的成本。

变量

变量分为:类变量、静态类变量、只读变量、静态只读变量、方法变量。

类变量:

private string _userName;

类变量只能使用 private 修饰符,如果需要暴漏出去,或是给子类使用,使用属性来进行封装。

静态类变量、只读变量、静态只读变量:

private static readonly ResourceManager _resourceManager;
public static readonly IRouter Instance = new MockRouter();

• 修饰符为 private: _ + 驼峰命名法;
• 修饰符为 public: Pascal 命名法;
• 修饰符为 protected:Pascal 命名法;

方法变量:

bool isCheck;

常量:

常量采用Pascal命名法:

public const string AuthorizationFilter = "Authorization Filter";

属性:

属性采用 Pascal 命名法:

public BasicApiContext DbContext { get; }

参数

参数采用驼峰命名法:

public List<BizApp> GetBizAppList(string userId,DeviceType deviceType)

注释规范

注释是一把双刃剑,当代码中存在大量的注释的时候,我们第一反应会先看注释,并会默认注释中写的内容是对的,真实情况是注释往往会给我们错误的指导。有两个原因:

  • 当代码逻辑发生变化时,只修改了代码,注释没有调整;

  • 不同的人员都对注释进行编辑,慢慢注释会变得和代码不匹配。

Martin Fowler 在他的经典书籍 《重构》 中也提到过多的注释是一种坏味道的体现,他认为,当你觉得需要写注释的时候,应该先想想是不是可以进行重构。那是不是程序中就不应该出现注释呢?当然不是,我认为下几种情况是需要写注释的:

  • 时间紧急,临时写的一些 ”烂代码“,需要写注释,说明原因,一般需要加上 TODO ;

  • 复杂算法类的方法,可以写注释说明逻辑;

  • 写的是偏底层的类库,对外暴露的方法需要写注释,调用方能方便在智能提示中显示;

  • 如果你的能力写不好代码,那还是先把注释写上吧。

异常规范

  • 异常的目的是用来报告错误,这也是他的唯一目的,所以避免在返回值中来返回错误信息,所有的地方都应该使用抛异常的方式来报告错误;

  • 使用抛异常的方式可以防止错误的操作继续执行;

  • 要能够预估到会出现什么异常,知道是什么类型的异常,才 Try 住做相关的处理;

  • 最终用户友好和对开发者友好;

  • 暴漏问题比隐藏问题要好,隐藏问题只会导致更严重的问题。

详细的异常处理可以参考之前的文章:

  • dotNET:怎样处理程序中的异常(理论篇)?

  • dotNET:怎样处理程序中的异常(实战篇)?

空行规范

空行规范是一个很简单的规范,就是在每个方法中,代码应该按照不同逻辑的逻辑块进行分割显示,虽然简单,但如果不注意,还是会对代码的阅读带来很大的障碍。下面看看 dotNET Core 的源码 CreateDefaultBuilder 方法:

public static IHostBuilder CreateDefaultBuilder(string[] args)
{var builder = new HostBuilder();builder.UseContentRoot(Directory.GetCurrentDirectory());builder.ConfigureHostConfiguration(config =>{config.AddEnvironmentVariables(prefix: "DOTNET_");if (args != null){config.AddCommandLine(args);}});builder.ConfigureAppConfiguration((hostingContext, config) =>{var env = hostingContext.HostingEnvironment;config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true).AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);if (env.IsDevelopment() && !string.IsNullOrEmpty(env.ApplicationName)){var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));if (appAssembly != null){config.AddUserSecrets(appAssembly, optional: true);}}config.AddEnvironmentVariables();if (args != null){config.AddCommandLine(args);}}).UseDefaultServiceProvider((context, options) =>{var isDevelopment = context.HostingEnvironment.IsDevelopment();options.ValidateScopes = isDevelopment;options.ValidateOnBuild = isDevelopment;});return builder;
}

想想看,上面代码中如果去掉空行会读起来是什么样的感受?

日志规范

在一个完整的系统中,日志非常的重要。在 dotNET Core 中自带了日志功能,当然我们也可以使用第三方的 NLog、Serillog 等。

这些日志框架都提供日志级别功能,比如:INFO、DEBUG、WARN 和 ERROR 等,这些级别对程序出错时的排查非常有用,所以在记录日志时一定不要都使用 INFO 或者都使用 ERROR 了。

除了级别,日志的类型有这么几类:

  • 操作日志

  • 业务日志

  • 错误日志

操作日志

系统中所有的操作的都记录下来,包括登录、数据的增删改等,主要用来做审计,数据异常操作时的追责等。

随着时间的推移,日志的数据量会越来越大,所以需要考虑存储的方式,比如阶段性地将历史日志进行存档。

业务日志

用户在界面中输入数据,点击一个按钮,程序中会进行一系列的处理最终返回结果给用户,在这个过程中对一些关键的业务信息进行记录,可以在系统出现问题时方便排查和追踪。

错误日志

错误日志的主要目的就是排错,所以记录的信息一定要是对排错有帮助的信息,尽可能地记录详细,比如整个堆栈信息、调用链等。比如,你去进行错误排查时,发现记录的信息是”未将对象引用到对象的实例“,你依然不知道错误的原因是什么。

总结

谈及代码的时候,都会去聊架构、模式,这些固然重要,但编码习惯和规范也不可小视。一份产品的代码怎样才能变得越来越好,这需要团队每个人成员共同的努力,一个人掉链子,很容易就形成破窗效应,导致坏味道越来越多。

写好的代码,是每个有追求的技术人的使命和职责。

希望本文对您有所帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/307686.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++ 学习之旅(16)——虚函数与纯虚函数virtual

关于虚函数的概念讲解&#xff0c;可以看这篇文章&#xff1a; https://blog.csdn.net/siwuxie095/article/details/71159414 以下用例子进行实际说明&#xff1a; #include <iostream> using namespace std;class Shape { public:int width, height;Shape(int a 0,…

.NET 5 自身就是一个 .NET Standard

微软2014年开源.NET的动作是实现一个全新的.NET Core ,从而引入了一个新的问题&#xff1a;选择代码的编译目标变得困难&#xff0c;需要面对3个环境。因此微软为了解决这个问题&#xff0c;引入了两个主要的概念&#xff1a;目标框架别名&#xff08;Target Framework Moniker…

Springboot后台管理(CRUD)

一:前言 这个就是用springboot实现后台管理(CRUD)的小demo,相比于SSM的配置地狱&#xff0c;springboot的自动配置确实很牛&#xff0c;tomcat都内置&#xff0c;我们想要修改相关的信息只要在yaml配置文件修改就行了&#xff0c;关于Dao层&#xff0c;这个mybatis-plus,quo实…

保护 .NET Core 项目的敏感信息

我们的项目中几乎都会有配置文件&#xff0c;里面可能会存储一些敏感信息&#xff0c;比如数据库连接字符串、第三方API的AppKey和SecretKey等。对于开源项目&#xff0c;这些敏感信息肯定不能随着源代码一起提交到托管平台。对于网站应用大多都是要部署到有公开IP的服务器上的…

matlab常用函数辨析

conv2() vs filter2() filter2做的是相关correlation&#xff0c;conv2做的是卷积convolution&#xff0c;卷积是会将模板翻转&#xff0c;而相关不会&#xff0c;具体看下面的例子 a magic(5)a 17 24 1 8 1523 5 7 14 164 6 13 20 …

背包(二维数组版和一维数组版)

一:前言 这是动态规划的经典题型&#xff0c;那么我们也是 按照动态规划五步走的策略分析的 确定dp数组的含义以及下标的含义确定dp数组的递推公式确定dp数组的初始化确定dp数组的遍历顺序举例验证&#xff08;如果不是做题可省略&#xff09; 二:二维数组 1:示例 2:dp数组…

Azure App Service 健康检查正式发布

点击上方蓝字关注“汪宇杰博客”原文&#xff1a;Jason Freeberg, Suwat Bodin翻译&#xff1a;汪宇杰导语通过App Service&#xff0c;可以在流量增加时自动将应用程序自动扩展到多个实例。这样可以提高您应用的吞吐量&#xff0c;但是如果其中一个实例发生未捕获的异常怎么办…

二叉树N叉数的前中后序遍历总结,python实现递归法和迭代法

关于二叉树的前序遍历&#xff08;preoder&#xff09;、中序遍历&#xff08;inorder&#xff09;和后序遍历&#xff08;postorder&#xff09;&#xff0c;实际上只需要记住&#xff1a;左子节点一定在右子节点的左边&#xff08;左右&#xff09;&#xff0c;所谓前中后序遍…

Azure Cosmos Db 介绍及演示

Azure Cosmos DB 是 Microsoft 提供的全球分布式多模型数据库服务。Cosmos DB是一种NoSql数据库&#xff0c;但是它兼容多种API。它支持SQL, MongoDB、Cassandra或 Gremlin&#xff0c;你可以挑选自己喜欢的方式进行存储跟访问。主要优势统包式全局分发凭借 Cosmos DB&#xff…

二叉树层序遍历(广度优先搜索)基础概念与经典题目(Leetcode题解-Python语言)

二叉树的广度优先搜索即从上到下、从左到右地进行搜索&#xff0c;对于层序遍历&#xff08;Level Order&#xff09;问题&#xff0c;即依次遍历第一层节点、第二层节点…等&#xff0c;基本可以秒杀。 广度优先搜索是通过队列来实现的&#xff0c;python中优先用collections…

leetcode049. 最后一块石头的重量 II

一:题目 二:上码 class Solution { public:/**思路:1.分析题意只要我们将石头分为尽可能相同的两堆,他们的重量相减后剩余的重量就是最小。 物品的重量为stones[i];物品的价值也为stone[i];temp代表总重量的一半那么我们最终得到的stones[temp]:就是背包容量为temp的最大重量为…

大改革,GNOME 3.x将直接跳到GNOME 40

GNOME 3.38 发布后&#xff0c;GNOME 基金会宣布了用于 GNOME 的新版本控制方案&#xff0c;将于2021年3月发布的下一版 GNOME 将是 GNOME 40。你没看错&#xff0c;版本号直接从现在的 3.x 跳到了 40。以 GNOME 40 为例&#xff0c;其开发周期将包含三个阶段&#xff0c;对应的…

从前中后序遍历构造二叉树,三题无脑秒杀

如果只是前中后序遍历的其中一种&#xff0c;是不可能唯一确定一个二叉树的&#xff0c;必须是其中两个的结合&#xff0c;由此便产生了三道题目&#xff0c;在这里可以全部秒杀。 需要记住的要点是&#xff1a; 前序&#xff08;根左右&#xff09;——第一个节点一定是根节点…

.NET Core + Kubernetes:StatefulSet

在 Kubernetes 中&#xff0c;Pod 资源的控制器 Deployment、Replicaset、Daemonset 等常用于管理无状态应用&#xff0c;它们所管理的 Pod 对应的 IP、名字&#xff0c;启停顺序等都是随机的&#xff0c;Pod 之间也并不存在任何关联关系。而实际情况下&#xff0c;在应用集群部…

哈希表(散列表)基础概念与经典题目(Leetcode题解-Python语言)之上——原理与设计

哈希表&#xff08;Hash table&#xff0c;也叫散列表&#xff09;&#xff0c;是根据键&#xff08;Key&#xff09;而直接访问数据在内存中的储存位置&#xff08;又叫做存储桶&#xff0c;Buckets&#xff09;的数据结构。也就是说&#xff0c;它通过计算一个关于键值的函数…

python编程中的小问题汇总

前言 本文记录了我在python编程中遇到的各种小问题&#xff0c;持续更新。 1. x x 1 VS x 1 辨析下面这两段代码&#xff1a; >>> x y [1, 2, 3, 4] >>> x [4] >>> x [1, 2, 3, 4, 4] >>> y [1, 2, 3, 4, 4]>>> x y …

都在讨论高并发,结果连并发量、TPS、QPS都分不清

“ 年年岁岁跳槽季&#xff0c;回回必问高并发&#xff01;原因很简单&#xff0c;因为高并发能牵扯出太多问题&#xff0c;接口响应超时、CPU负载升高、GC频繁、死锁、大数据量存储等&#xff0c;能考察求职者的真实情况。而很多人在第一步就倒下了&#xff01;因为对数据化的…

哈希表(散列表)基础概念与经典题目(Leetcode题解-Python语言)之中——实际应用

上一节介绍了哈希表的原理与设计方法&#xff0c;这一节则直接python中现有的哈希表类型&#xff1a;哈希集合 set&#xff08;集合&#xff09;和哈希映射 dict&#xff08;字典&#xff09;来解决实际应用&#xff08;刷题&#xff09;。 零、概念 在介绍实际应用之前&#…

leetcode518. 零钱兑换 II

一:题目 二:上码 class Solution { public:/**思路:1.分析题意这个满足答案的结果有很多种&#xff0c;所以我们可以用动态规划去做,那么题意中我们可以知道的是我们是可以输入一种面值的时候,我们是可以重复输入的&#xff0c;那么这就是背包类型中的完全背包了2.动态规划5步…

跟我一起学.NetCore之选项(Options)核心类型简介

前言.NetCore中提供的选项框架&#xff0c;我把其理解为配置组&#xff0c;主要是将服务中可供配置的项提取出来&#xff0c;封装成一个类型&#xff1b;从而服务可根据应用场景进行相关配置项的设置来满足需求&#xff0c;其中使用了依赖注入的形式&#xff0c;使得更加简单、…