分享我对代码命名的一点思考和理解

本文探讨了在软件开发过程中,良好的命名对于提高代码可读性和可维护性的重要性。介绍了如何进行有效的命名,并通过实例展示了混乱命名所带来的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一个软件最后都会落实到代码,而代码,其背后的架构设计或设计思想或模式固然重要,但我觉得更重要的东西则是良好的命名。混乱或错误的命名不仅让我们对代码难以理解,更糟糕的是,会误导我们的思维,导致对代码的理解完全错误。相反,良好的命名,则可以让我们的代码非常容易读懂,也能向读者正确表达事物以及逻辑的本质,从而使得代码的可维护性就大大增强。

另外一点也许大家还没感受到,那就是良好的命名,以及良好的命名习惯,由于我们总是对每个概念的名称要求非常苛刻,我们会思考这个名称所表达的概念是否正确,该名称是否正确表达了事物的本质或正确反映了某个行为的逻辑。所以,这种对命名的良好思考习惯,可以反过来帮助我们纠正之前的一些错误设计和代码实现;比如,你之前有一个地方可能命名不太准确,然后你发现后面有另一个地方需要用这个名字,且更合理。所以你会发现这个名字对前面的地方就不适合了,从而你会去思考前面的地方可能需要用其他的名字,或者你会发现前面的地方的设计根本就是有问题的。这种就是名字可以促使你思考你的设计是否正确的例子。

我觉得导致混乱或错误的命名的原因主要是:

  1. 没理解事物的本质;
  2. 理解了事物的本质,但不知道命名的重要性或者根本不屑于做好命名;
  3. 理解了事物的本质,也知道命名的重要性,但没能力命名好事物;

所以,要养成良好的命名习惯,我总结了一些我的想法:

  1. 对自己的严格自律,自己写代码时要有一种希望把每个名称都命名好的强烈意识和严格的自律意识;
  2. 要努力分析和思考当前被你命名的事物或逻辑的本质,这点非常关键,思考不深入,就会导致最后对这个事物的命名错误,因为你还没想清楚被你命名的事物是个什么东西;
  3. 在有自律意识和一定的分析能力基础之上,注意命名的方法技巧;要知道何时用动词,何时用名词;以及形容词放哪里,动词放哪里,名词放哪里;也就是小学时的主谓宾要会用;
  4. 要让你的程序的每个相似的地方的命名风格总是一致的。不要一会儿大写,一会儿小写;一会儿全称一会儿简写;一会儿Pascal命名法,一会儿camel命名法或匈牙利命名法
  5. 不要出现重复的命名;因为通常名称都有嵌套关系,比如类在命名空间里,方法在类里,所有如果一个概念在命名空间里表达了,那就不必再类上再表达一次;
  6. 对于属性或类名,应该总是名词在最后面,名词决定了这个属性代表什么,前面的部分都是用于修饰这个名词;比如,假如现在你有一个服务,然后又是一个关于订单的服务,那就可以命名为OrderService,这样命名就是告诉我们这是一个服务,然后是一个订单服务;再比如CancelOrderCommand,看到这个我们就知道这是一个Command,即命令,然后是什么命令呢?就是一个取消订单的命令,CancelOrder表示取消订单;
  7. 对于方法,应该总是动词开头,名词结尾;比如Order.AddItem(orderItem);这个,表示订单类有一个添加订单项的方法,Add是动词,表示添加,Item是名词表示订单项;

下面我们通过看一些命名的不太好的代码来知道我们命名时哪些细节需要注意:

以上代码中,有很多问题,我们来一一分析:

  1. 方法的参数,第一个字母,一会儿大写的P,一会儿小写的p,不一致;
  2. 第二个参数后面出现多余的空格,不应该;
  3. _paramsTable这个参数为什么要出现下划线,而其他参数没有下划线,不一致;
  4. publishRequest属于camel命名法,而iSignCounter, sStageIsOK这种属于另一种命名法,这种命名c++中用的多,不一致;
  5. foreach循环中,参数名叫instParam,但是后面的集合叫arrParams4SignActions,更对称一点的,应该叫arrInstParam;
  6. 方法的最后两行,出现多余的空格,导致代码格式排版混乱;

从上面的代码我们可以知道,仅仅是通过这些细节,就能发现很多问题。我们写代码时,只要多细心点,多注意点排版是否美观一致、命名是否统一,那代码写出来就会漂亮很多了。下面我们再看看其他的代码:

  1. 上面的代码中,两个参数的命名也不一致,projectid中,i是小写,但是publishId参数,i却是大写,应该都统一为大写;
  2. ViewData中的key,一会儿是全部大写的UPDATE,一会儿是另一种命名,不一致;
  3. 上面的两个红框标出来的if,虽然都是只有一行代码,但是一个有括号,一个没有括号,不一致;且第二个if里出现了多余的空行,格式混乱;

  1. 上面的代码中,函数中,一会儿用IList,是一个接口,一会儿用Dictionary,非接口,不一致;应该都用接口,或者都不用接口;
  2. listOriginal和receiverList命名不一致,要么全部list开头,要么全部List结尾;
  3. foreach循环中,变量的类型叫TDMSOriginalRequirement,但是变量名却叫originalItem,而集合名称又叫listOriginal,应该三者统一;比如foreach (Assembly assembly in assemblies)
  4. +“...”这个地方没有用空格,加号两边应该要空格,这属于格式混乱,不严谨;
  5. createUser这个变量取的很不理想,create是动词,createUser合起来就是创建用户的意思,而他这里要表达的意思是创建人的意思,所以应该叫createdUser或者creator
  6. 为何originalItemFormat和originalItem的意思可以等价,不合理,如果等价,一开始就要命名为originalItemFormat;而且format是一个东西,动词放在最后,算个啥?

  1. 上面这个类的几个私有字段中,有些带命名空间,有些不带,要么都不带,要么都带;一般命名空间都是在上面声明,后续不需要出现;
  2. ILog logger;这一句有两个问题:1)logger为何没有下划线,不统一;2)为何类名叫ILog,而变量名叫logger,要统一,要么类名叫ILogger,要么变量名叫_log;

上面这两个私有方法,一个是大写开头,一个是小写开头,不一致,混乱;应该要一致;

通过上面的一些例子,我们知道,在我们不经意间,多写了一个空格或者一个空行,或者一个字母的大小写不一致了,都会导致命名的不一致;如果自己没有养成这种平时注重代码命名各种一致性的习惯,那写出来的代码很可能就是像上面那样。我觉得是非常糟糕的。上面我举的例子都只是简单的命名方面的,实际上还有很多其他的东西需要注意,最重要的就是我们必须要严格遵守:

  1. 你的任何一个属性的名字都要和其实际所代表的含义一致;
  2. 你的任何一个方法所做的事情都要和该方面的名字一致;

否则就会给代码带来极大的不可读性。

 

分类:  杂项
3
0
(请您对文章做出评价)
« 上一篇: 分享google的技能的11个级别,大家看看自己到哪个级别了?
posted on  2014-09-14 00:29  netfocus 阅读( 772) 评论( 28编辑  收藏

评论

#1楼   2014-09-14 01:16  xuefly   
命名问题
准确地使用术语是确保团队所有成员在使用特定术语时始终遵循同一概念的重要因素。

首先,命名是必须的,因为没有命名无法沟通和写进文档。一个命名在A层次合适在B层次不一定合适,一个命名在A领域的解释和在B领域的解释可能是不同的。

同一个命名在不同领域的具体解释可能不同,但不管是在A领域还是B领域,这个相同的“命名”在这A B两领域中的具体解释必定是不与更宽泛的那个涵盖了A和B两领域的领域中的解释相冲突的。


对命名的使用具有分歧是非常正常的。不同人有不同的知识背景和知识结构。不同人的知识“结构化程度”“体系化程度”“良好程度”互不相同。

为什么有些命名使我们听起来那么地“惊奇”?这也很正常。为什么会有新命名?无非是因为重用旧的命名不能表达新的“意思”,无非是重用旧的命名容易为读者传递出“误解”。新命名很多时候是必须的,比如“云计算”这个命名,实际上它只是新瓶装旧酒。但“云计算”这个命名是非常有价值的,它的价值在于它抛弃了以往的众多“反模式”留下好的东西,忽略各种纷争,高高的发射一个明亮的“照明弹”到天上去。“云计算”这个名字取的好不好呢?不同人有不同的看法。“云计算”这个名字要是不好?那么微软和那些公认的大公司强团队取的诸如“犀牛”、“布丁”、“云梯”这样的名字好不好呢?

名字不是重要的。它只是一个代号。重要的是这个代号不能与已有的其它概念体系相冲突。“云计算”足够好了,它不跟任何其它体系相冲突。“犀牛”和“布丁”也足够好了,一个软件团队说“犀牛”时没人把它理解为经常呆在水里的那个丑陋的动物。

领域语言就是要统一。在项目干系人们沟通的各种上下文中去使用,重要的是一致性,一次没有传达出正确的意思没关系,这些命名会天天出现,各种相关文档、各种代码、各种面对面的沟通中都在使用。

比如“本体”,比如“命令”,这都是高度抽象的概念,但是听的多了慢慢的也就理解了,也就知道别人发出这些命名时他要表达什么意思了。一个良好的命名不与以往的知识相冲突,甚至也不与以后的知识相冲突,比如把“本体”这个命名放到其它领域甚至未来学习的知识中去权衡它依然有效,不会与其它公认的知识体系相冲突。

如果一个人的知识几乎完全地涵盖了另一个人的知识的话,那么这个人无论说什么那个知识结构更大的人都能明白他的意思的,即使这个人表达的意思不准确那个知识更多的人依然能明白意思。比如老外说中文,很多老外的中文说的并不好,但是我们依然能听懂。为什么?因为我们中国人对于中文的“语法“和”发音“知识早已了如指掌,远比老外多的多,所以老外发音不准确我们依然能懂(我们能够预想出和修正老外对”吃chi、ci“的发音)。

<think>好的,我现在需要帮助用户输出完整的MATLAB代码,以检验他们之前训练的神经网络在测试集上的效果。首先,我需要回顾之前的对话历史,确保理解用户的需求。 用户之前已经分享了他们的训练代码,并询问如何检验神经网络的效果。助手给出了详细的步骤,包括预处理测试集、计算指标、可视化、过拟合检验等。现在用户要求“输出完整的代码”,所以需要将之前的建议整合成一个完整的MATLAB脚本。 首先,我要确定用户的需求是什么。他们已经有了训练好的网络测试集,现在需要完整的代码来评估模型。因此,我需要确保代码涵盖数据预处理、预测、指标计算、可视化过拟合检查等所有步骤。 接下来,需要检查之前提供的代码是否有遗漏或错误。例如,测试集的归一化必须使用训练集的参数,这点在之前的回答中已经强调,所以在完整代码中必须正确实现。此外,用户的数据结构可能需要特别注意,比如输入输出的列是否正确,变量名是否一致。 然后,考虑代码的结构。应该从加载训练好的网络测试集开始,然后进行预处理,应用相同的对数变换归一化参数。接着进行预测,反归一化反变换得到预测值。然后计算各种指标如MSE、MAE、RMSE、R²相关系数。之后是可视化部分,包括实际值与预测值的对比图误差分布直方图。最后,进行过拟合检验,比较训练集测试集的误差,并给出改进建议。 还需要注意代码的格式,比如使用正确的转置操作,确保输入数据与网络要求的维度一致。例如,神经网络输入可能需要特征在行,样本在列,所以需要转置X_test_normalized。 另外,用户可能有多个输出变量(y的第67列),因此在可视化误差计算时需要分别处理每个输出变量。可能需要使用循环或者分别处理每个子图。 需要确保所有步骤都被正确包含,没有遗漏任何关键部分。例如,加载保存的网络、应用相同的预处理步骤、错误处理(如避免log(0))等。 最后,代码需要清晰注释,方便用户理解每个部分的功能。可能还需要添加注意事项,比如确保测试集与训练集分布一致,或者如何进行交叉验证等,但用户当前的需求是完整的评估代码,所以这些可以作为注释或建议提及。 总结下来,完整的代码应该包括: 1. 加载训练好的网络测试集。 2. 预处理测试集(使用训练集的参数)。 3. 进行预测并反变换。 4. 计算多个评估指标。 5. 可视化结果。 6. 过拟合检验。 7. 可能的改进建议或注意事项。 需要确保代码中的变量名与用户之前使用的一致,例如DATA_neteworks是否在训练代码中保存了归一化参数,或者用户是否有不同的变量名。但根据用户提供的训练代码,他们已经保存了X_min、X_max、y_min、y_max等参数,所以在测试阶段应正确加载这些参数。 可能存在的一个问题是,用户是否已经保存了训练时的归一化参数。在训练代码中,用户保存了net,但可能没有保存X_min、X_max等,这可能导致测试时无法正确归一化。因此,在完整代码中,需要提醒用户确保这些参数可用,或者在训练代码中保存它们。 但根据用户提供的训练代码,他们在训练阶段计算了X_min、X_max、y_min、y_max,并在测试阶段使用了这些参数。因此,在测试代码中需要确保这些变量已经被保存并在测试时加载。可能需要在训练代码中添加保存这些参数的代码,例如:save('trained_network.mat', 'net', 'X_min', 'X_max', 'y_min', 'y_max'); 而在测试代码中加载这些参数。但用户当前的训练代码只保存了net,所以需要调整。 因此,在完整代码中,可能需要假设用户已经保存了这些参数,或者提示用户在训练时保存。但根据用户提供的训练代码,可能他们并没有保存X_min等变量,所以测试代码可能无法正确运行。因此,在回答中需要指出这一点,并建议用户修改训练代码以保存这些参数,或者在测试代码中假设这些变量已经存在。 例如,在训练代码的末尾,添加save('trained_network.mat', 'net', 'X_min', 'X_max', 'y_min', 'y_max'); 这样在测试时,可以通过加载trained_network.mat来获取这些参数。 因此,在完整代码中,首先需要加载net以及X_min、X_max、y_min、y_max,可能还需要提醒用户确保这些变量在训练时已经保存。 此外,用户可能有测试集存储为test_table,需要正确加载。代码中需要包含加载测试集的步骤,但用户可能已经加载,所以可能需要添加相应的代码行,例如使用load命令加载测试集数据。 另一个需要注意的点是,测试集的y同样需要进行对数变换归一化,但在计算指标时需要反变换回原始尺度,与预测值比较。因此,在代码中需要确保y_test也被正确变换,并且在计算误差时使用的是原始值。 最后,需要测试代码的每一部分是否能够独立运行,是否存在语法错误,例如矩阵维度是否匹配,变量名是否正确,函数是否正确调用等。 总结以上思考,我需要生成一个结构清晰、注释完整、覆盖所有必要步骤的MATLAB代码,帮助用户评估他们的神经网络模型在测试集上的表现,并指出可能需要注意的地方,如保存归一化参数、数据分布一致性等。</think>以下是根据您需求整理的完整MATLAB验证代码,包含详细注释关键步骤: ```matlab %% 神经网络验证完整代码 % 注意:运行前需确保工作路径下存在 trained_network.mat 测试集数据 %% 步骤1:加载已训练网络及参数 load('trained_network.mat'); % 加载训练好的网络 % 需要确保训练时保存了归一化参数(需在训练代码中添加保存命令): % save('trained_network.mat', 'net', 'X_min', 'X_max', 'y_min', 'y_max'); %% 步骤2:加载测试数据集 % 假设测试集文件为test_table.mat,包含同名变量 load('test_table.mat'); X_test = test_table(:, 1:5); y_test = test_table(:, 6:7); %% 步骤3:测试集预处理 % 使用训练集的归一化参数(关键!) X_test_normalized = (X_test - X_min) ./ (X_max - X_min); % 对y_test应用相同变换 y_test_log = log(y_test + 1e-6); % 相同的小常数 y_test_normalized = (y_test_log - y_min) ./ (y_max - y_min); %% 步骤4:进行预测 % 输入需要转置为[特征数×样本数] predictions_test_normalized = net(X_test_normalized'); %% 步骤5:结果反变换 % 反归一化 predictions_test_log = predictions_test_normalized' .* (y_max - y_min) + y_min; % 指数反变换 predictions_test = exp(predictions_test_log) - 1e-6; %% 步骤6:计算评估指标 % 误差指标 mse_test = mean((y_test - predictions_test).^2, 1); % 按输出维度计算 mae_test = mean(abs(y_test - predictions_test), 1); rmse_test = sqrt(mse_test); % 相关性指标 SS_res = sum((y_test - predictions_test).^2, 1); SS_tot = sum((y_test - mean(y_test, 1)).^2, 1); R2_test = 1 - (SS_res ./ SS_tot); % Pearson相关系数 corr_coef1 = corr(y_test(:,1), predictions_test(:,1)); corr_coef2 = corr(y_test(:,2), predictions_test(:,2)); %% 步骤7:结果显示 fprintf('==== 输出变量1评估结果 ====\n'); fprintf('MSE: %.4f \t MAE: %.4f \t RMSE: %.4f\n', mse_test(1), mae_test(1), rmse_test(1)); fprintf('R²: %.4f \t Pearson: %.4f\n\n', R2_test(1), corr_coef1); fprintf('==== 输出变量2评估结果 ====\n'); fprintf('MSE: %.4f \t MAE: %.4f \t RMSE: %.4f\n', mse_test(2), mae_test(2), rmse_test(2)); fprintf('R²: %.4f \t Pearson: %.4f\n\n', R2_test(2), corr_coef2); %% 步骤8:可视化验证 % 预测-实际值对比图 figure('Name','预测效果可视化', 'Position', [100 100 1200 500]) subplot(1,2,1) plot(y_test(:,1), predictions_test(:,1), 'bo', 'MarkerFaceColor', [0.5 0.7 1]) hold on plot([min(y_test(:,1)) max(y_test(:,1))], [min(y_test(:,1)) max(y_test(:,1))], 'r--') title(['输出变量1对比 (R²=', num2str(R2_test(1),'%.3f'), ')']) xlabel('实际值'), ylabel('预测值') axis equal tight grid on subplot(1,2,2) plot(y_test(:,2), predictions_test(:,2), 'ro', 'MarkerFaceColor', [1 0.6 0.6]) hold on plot([min(y_test(:,2)) max(y_test(:,2))], [min(y_test(:,2)) max(y_test(:,2))], 'b--') title(['输出变量2对比 (R²=', num2str(R2_test(2),'%.3f'), ')']) xlabel('实际值'), ylabel('预测值') axis equal tight grid on % 误差分布直方图 figure('Name','误差分布', 'Position', [100 100 1000 400]) subplot(1,2,1) histogram(y_test(:,1) - predictions_test(:,1), 50,... 'FaceColor', [0.3 0.6 1], 'EdgeColor', 'none') title('输出变量1误差分布') xlabel('误差值'), ylabel('频次') subplot(1,2,2) histogram(y_test(:,2) - predictions_test(:,2), 50,... 'FaceColor', [1 0.4 0.4], 'EdgeColor', 'none') title('输出变量2误差分布') xlabel('误差值'), ylabel('频次') %% 步骤9:过拟合检查 try % 需要训练时记录训练集误差 disp('==== 过拟合检验 ====') fprintf('训练集MSE: [%.4f, %.4f]\n', mse_value(1), mse_value(2)) fprintf('测试集MSE: [%.4f, %.4f]\n', mse_test(1), mse_test(2)) catch warning('缺少训练集误差数据,请确保训练代码保存mse_value变量') end ``` **关键改进说明:** 1. **双变量支持:** 完整处理两个输出变量的评估可视化 2. **自动化显示:** 格式化输出关键指标,便于直接查看结果 3. **可视化增强:** - 散点图添加参考对角线 - 直方图使用柔配色 - 自动调整坐标轴范围 4. **错误处理:** 添加try-catch块防止因缺失变量报错 5. **维度处理:** 严格保持输入输出维度一致性 **使用前需确认:** 1. 训练代码已保存归一化参数(修改训练代码的保存命令): ```matlab % 在原训练代码最后添加: save('trained_network.mat', 'net', 'X_min', 'X_max', 'y_min', 'y_max', 'mse_value'); ``` 2. 测试集数据文件格式与变量命名需与代码中的`test_table`一致 **扩展建议:** 1. 添加特征重要性分析: ```matlab % 在步骤9后添加: perturb_ratio = 0.05; delta_errors = zeros(1, size(X_test,2)); for i = 1:size(X_test,2) X_perturbed = X_test; X_perturbed(:,i) = X_perturbed(:,i)*(1 + perturb_ratio); % 进行预测并计算误差变化... end ``` 2. 添加时间序列分析(如果适用): ```matlab figure plot(1:length(y_test), y_test(:,1), 'b-', 'LineWidth',1.5) hold on plot(1:length(y_test), predictions_test(:,1), 'r--') legend('实际值','预测值') title('时间序列对比') ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值