5条易于阅读的代码规则

您问自己:“如何清晰清晰地书写?” 如何快速找出别人的代码?”

记住并遵守以下规则!

本文不讨论变量和函数的命名的基本规则,句法缩进以及大型重构主题。 我们考虑5条简单的规则,以简化代码并减少开发过程中的大脑负担。

考虑感知数据的过程,以将描述的规则与感知过程相关联,并确定简单代码的标准。

感知的简化过程包括以下步骤:

  1. 通过接收器接收的数据与以前的经验一致。
  2. 如果没有相关性,那就是噪音。 噪音很快就被遗忘了。 如果有任何相关的事实,则可以识别事实。
  3. 如果事实很重要-例如,我们记得,概括或行动,我们说或键入代码。
  4. 为了减少记忆和分析的信息量,使用了归纳法。
  5. 汇总后,再次对信息进行关联和分析(步骤1)。


科学家将记忆分为短期和长期。 短期存储量很小,但是信息会立即提取并存储。 短期记忆是大脑的缓存。 它可以存储7 + -2个单词,数字,对象。 长期存储器的容量更大,但是与短期存储器相比,它需要更多的精力(精力)来保存和检索信息。

结论:

  • 元素越少,花费的能量就越少,
  • 需要将感知元素的数量减少到9
  • 使用尽可能少的长期记忆:泛化或忘记。

我们继续对规则进行描述。

规则1.我们在条件中使用该语句,以摆脱“不”。

删除“非”运算符可以减少要分析的元素的数量。 同样,在许多编程语言中,否定运算符使用“!”。 阅读代码时,容易跳过此字符。

比较:

if (!entity.IsImportAvaible) { // 1 } else { // 2 } 

之后:

 if (entity.IsImportAvaible) { // 2 } else { // 1 } 

规则2.减少嵌套级别。

在代码分析期间,每个嵌套级别都需要保留在内存中。 减少等级数量-降低燃料成本。

考虑减少嵌套级别的方法。

1)返回控制。 我们切断了一些案例,将重点放在其余的案例上。

 if (conributor != null) { // } 

转换成

 if(contributor == null) { return; } // 



 while( 1) { if( 2) { break; } // } 



 for(; 1;) { if( 2) { continue; } // } 

规则5中给出了扩展示例。请注意引发异常。

2)方法的隔离。 函数的名称是泛化的结果。

 if( ) { foreach(var sender in senders) { sender.Send(message); } } 



 if( ) { SendAll(senders, message); } void SendAll(IEnumerable<Sender> senders, string message) { foreach(var sender in senders) { sender.Send(message); } } 

3)结合条件。

 if (contributor == null) { if (accessMngr == null) { // } } 



 if (contributor == null && accessMngr == null) { // } 

4)删除变量并划分为语义块。 结果,可以独立更改块,最重要的是,阅读和理解此类代码要容易得多。 一站式-一种功能。 常见的情况是带有处理的搜索。 有必要将代码分成单独的语义块:元素搜索,处理。

 for (int i=0;i<array.length;i++) { if (array[i] == findItem) { // array[i] break; } } 



 for(int i=0;i<array.length;i++) { if(array[i] == findItem) { foundItem =array[i]; break; } } if (foundItem != null) { // foundItem } 

规则3。我们摆脱了索引器和通过属性进行调用。

索引器-在索引arr [index]处访问数组元素的操作。

在感知代码的过程中,大脑使用符号[]作为定界符,并使用索引器作为表达式进行操作。

 function updateActiveColumnsSetting(fieldsGroups) { var result = {}; for (var i = 0; i < fieldsGroups.length; i++) { var fields = fieldsGroups[i].fields; for (var j = 0; j < fields.length; j++) { if (!result[fieldsGroups[i].groupName]) { result[fieldsGroups[j].groupName] = {}; } result[fieldsGroups[i].groupName][fields[j].field] = createColumnAttributes(j, fields[j].isActive); } } return JSON.stringify(result); } 

索引器是经常出错的地方。 由于索引名短,因此很容易混淆I,j或k。

在上面的示例中,在行结果中[fieldsGroups [j] .groupName] = {}; 错误:
使用j代替i。

为了找到确切使用第i个值的位置,您必须:

1)在视觉上突出显示数组变量

 function updateActiveColumnsSetting(fieldsGroups) { var result = {}; for (var i = 0; i < fieldsGroups.length; i++) { var fields = fieldsGroups[i].fields; for (var j = 0; j < fields.length; j++) { if (!result[fieldsGroups[i].groupName]) { result[fieldsGroups[j].groupName] = {}; } result[fieldsGroups[i].groupName][fields[j].field] = createColumnAttributes(j, fields[j].isActive); } } return JSON.stringify(result); } 

2)分析每次出现的情况,以使用所需的索引器I,j,i-1,j-1等,同时牢记索引器的使用位置和已识别的参考索引。
通过突出显示变量中的索引器,我们可以减少危险位置的数量,并且可以轻松地使用大脑来感知变量,而无需记忆。

处理后:

 function updateActiveColumnsSetting(fieldsGroups) { var columnsGroups = {}; for (var i = 0; i < fieldsGroups.length; i++) { var fieldsGroup = fieldsGroups[i]; var groupName = fieldsGroup.groupName; var columnsGroup = columnsGroups[groupName]; if (!columnsGroup) { columnsGroup = columnsGroups[groupName] = {}; } var fields = fieldsGroup.fields; for (var j = 0; j < fields.length; j++) { var fieldInfo = fields[j]; columnsGroup[fieldInfo.field] = createColumnAttributes(j, field.isActive); } } return columnsGroups; } 

视觉选择更加简单,现代开发环境和编辑器通过突出显示代码不同部分中的子字符串来提供帮助。

 function updateActiveColumnsSetting(fieldsGroups) { var columnsGroups = {}; for (var i = 0; i < fieldsGroups.length; i++) { var fieldsGroup = fieldsGroups[i]; var groupName = fieldsGroup.groupName; var columnsGroup = columnsGroups[groupName]; if (!columnsGroup) { columnsGroup = columnsGroups[groupName] = {}; } var fields = fieldsGroup.fields; for (var j = 0; j < fields.length; j++) { var fieldInfo = fields[j]; columnsGroup[fieldInfo.field] = createColumnAttributes(j, field.isActive); } } return columnsGroups; } 

规则4.根据含义对块进行分组。

我们使用感知的心理效应-“接近效应”:感知中紧密间隔的人物相结合。 为了使代码为感知过程中的分析和泛化做好准备,并减少存储在内存中的信息量,您可以按含义排列或在功能上紧密结合,用空行将其分隔开来排列附近的行。

至:

 foreach(var abcFactInfo in abcFactInfos) { var currentFact = abcInfoManager.GetFact(abcFactInfo); var percentage = GetPercentage(summaryFact, currentFact); abcInfoManager.SetPercentage(abcFactInfo, percentage); accumPercentage += percentage; abcInfoManager.SetAccumulatedPercentage(abcFactInfo, accumPercentage); var category = GetAbcCategory(accumPercentage, categoryDictionary); abcInfoManager.SetCategory(abcFactInfo, category); } 

之后:

 foreach (var abcFactInfo in abcFactInfos) { var currentFact = abcInfoManager.GetFact (abcFactInfo); var percentage = GetPercentage(summaryFact, currentFact); accumPercentage += percentage; var category = GetAbcCategory(accumPercentage, categoryDictionary); abcInfoManager.SetPercentage(abcFactInfo, percentage); abcInfoManager.SetAccumulatedPercentage(abcFactInfo, accumPercentage); abcInfoManager.SetCategory(abcFactInfo, category); } 

在上面的示例中,有7个块,在下面的3中:获取值,循环累积,设置管理器属性。

缩进有助于识别值得关注的位置。 所以,线

 accumPercentage += percentage; var category = GetAbcCategory(accumPercentage, categoryDictionary); 

除了依赖于先前的计算之外,它们还会将值累加到累计变量Percentage中。 为了强调差异,将代码缩进。

规则的一种特殊用例是声明局部变量,使其尽可能靠近使用地点。

规则5.遵循唯一性原则。

这是OOP中SOLID原则的第一个,但是除类外,它还可以应用于项目,模块,功能,代码块,项目团队或单个开发人员。 当被问到谁或什么负责该领域时,立即清楚是谁或什么。 一个连接总是很简单。 每个类别都被概括为一个概念,短语,隐喻。 结果,无需记住,感知过程变得更容易,更有效。

最后,一个综合的例子:

 private PartnerState GetPartnerStateForUpdate( PartnerActivityInfo partner, Dictionary<int, PartnerState> currentStates, Dictionary<int, PartnerState> prevStates) { PartnerState updatingState; if (prevStates.ContainsKey(partner.id)) { if (currentStates.ContainsKey(partner.id)) { var prevState = prevStates[partner.id]; updatingState = currentStates[partner.id]; // 1 } else { // 2 } } else if (currentStates.ContainsKey(partner.id)) { updatingState = currentStates[partner.id]; } else { throw new Exception(string.Format("  {0}         {1}", partner.id, month)); } return updatingState; } 

在替换了ContainsKe索引器,反转分支,选择方法并降低嵌套级别之后,结果是:

 private PartnerState GetPartnerStateForUpdate( PartnerActivityInfo partner, Dictionary<int, PartnerState> currentStates, Dictionary<int, PartnerState> prevStates) { PartnerState currentState = null; PartnerState prevState = null; prevStates.TryGetValue(partner.id, out prevState); currentStates.TryGetValue(partner.id, out currentState); currentState = CombineStates(currentState, prevState); return currentState; } private PartnerState CombineStates( PartnerState currentState, PartnerState prevState) { if (currentState == null && prevState == null) { throw new Exception(string.Format( "  {0}         {1}" , partner.id, month)); } if (currentState == null) { // 1 } else if (prevState != null) { // } return currentState; } 

第一个功能负责从字典中获取状态,第二个功能将它们组合成一个新的状态。

给出的规则很简单,但是结合起来,它们提供了一个强大的工具,可以简化代码并减少开发过程中的内存负载。 您将无法始终遵循它们,但是,如果您意识到自己不了解该代码,则最容易从它们开始。 他们在最困难的情况下一再帮助提交人。

Source: https://habr.com/ru/post/zh-CN436160/


All Articles