我的高级同事阻止我进行代码审查,因为他希望我将方法命名为“ PerformSqlClient216147Workaround”,因为这是某些缺陷的解决方法。现在,我的方法名称建议类似于PerformRightExpressionCast,它倾向于描述该方法的实际作用。他的论点是这样的:“这种方法仅在这种情况下用作解决方法,而在其他地方则没有。”
在临时解决方法的方法名称中包含错误号是否被视为不良做法?
我的高级同事阻止我进行代码审查,因为他希望我将方法命名为“ PerformSqlClient216147Workaround”,因为这是某些缺陷的解决方法。现在,我的方法名称建议类似于PerformRightExpressionCast,它倾向于描述该方法的实际作用。他的论点是这样的:“这种方法仅在这种情况下用作解决方法,而在其他地方则没有。”
在临时解决方法的方法名称中包含错误号是否被视为不良做法?
Answers:
我不会按照您的同事的建议来命名该方法。方法名称应指示方法的作用。类似的名称PerformSqlClient216147Workaround
并不表示其功能。如果有的话,请使用描述方法的注释来提及它是一种解决方法。看起来可能如下所示:
/**
* Cast given right-hand SQL expression.
*
* Note: This is a workaround for an SQL client defect (#216147).
*/
public void CastRightExpression(SqlExpression rightExpression)
{
...
}
我同意MainMa的观点,错误/缺陷号不应出现在源代码本身中,而应出现在源代码控制注释中,因为这是元数据,但是如果它们出现在源代码注释中并不可怕。错误/缺陷编号绝对不能在方法名称中使用。
@Workaround(216147)
@warning This is a temporary hack to...
或TODO: fix for ...
没有比临时修复有效的方法更永久了。
他的建议在十年后看起来不错吗?通常,通常都会在修正了每个缺陷的情况下对每个更改进行注释。最近(例如最近的30年),这种样式注释已被广泛接受,因为它降低了代码的可维护性-即仅注释而不是方法名称。
他的提议是有力的证据证明您的QC和QA系统严重不足。缺陷和缺陷修复程序的跟踪属于缺陷跟踪系统,而不是源代码。跟踪源代码更改属于源控制系统。这些系统之间的交叉引用允许将缺陷跟踪到源代码.....
源代码是今天的,不是昨天的,也不是明天的(例如,您没有键入明年计划做的事情)...
Nothing is more permanent than a temporary fix that works.
所以这是一个临时解决方案?然后使用审阅者建议的名称,但将方法标记为过时,以便每次有人编译代码时使用该方法都会产生警告。
如果不是,您可能总是会说这216147
在代码中是没有意义的,因为代码没有链接到错误跟踪系统(而是链接到源代码控件的错误跟踪系统)。源代码不是引用bug票证和版本的好地方,如果您确实需要将这些引用放在此处,请在注释中进行处理。
请注意,即使在注释中,仅bug号也不是很有价值。想象以下评论:
public IEnumerable<Report> FindReportsByDateOnly(DateTime date)
{
// The following method replaces FindReportByDate, because of the bug 8247 in the
// reporting system.
var dateOnly = new DateTime(date.Year, date.Month, date.Day);
return this.FindReportByDate(dateOnly);
}
private IEnumerable<Report> FindReportsByDate(DateTime date)
{
Contract.Requires(date.Hour == 0);
Contract.Requires(date.Minute == 0);
Contract.Requires(date.Second == 0);
// TODO: Do the actual work.
}
想象一下,该代码是十年前编写的,您刚刚加入该项目,并且当您问到哪里可以找到有关错误8247的任何信息时,您的同事告诉您,该错误的网站上有一个错误列表。报告系统软件,但该网站是在五年前重做的,而新的错误列表有不同的数字。
结论:您不知道此错误是关于什么的。
相同的代码可能以略有不同的方式编写:
public IEnumerable<Report> FindReportsByDateOnly(DateTime date)
{
// The reporting system we actually use is buggy when it comes to searching for a report
// when the DateTime contains not only a date, but also a time.
// For example, if looking for reports from `new DateTime(2011, 6, 9)` (June 9th, 2011)
// gives three reports, searching for reports from `new DateTime(2011, 6, 9, 8, 32, 0)`
// (June 9th, 2011, 8:32 AM) would always return an empty set (instead of isolating the
// date part, or at least be kind and throw an exception).
// See also: http://example.com/support/reporting-software/bug/8247
var dateOnly = new DateTime(date.Year, date.Month, date.Day);
return this.FindReportsByDate(dateOnly);
}
private IEnumerable<Report> FindReportsByDate(DateTime date)
{
Contract.Requires(date.Hour == 0);
Contract.Requires(date.Minute == 0);
Contract.Requires(date.Second == 0);
// TODO: Do the actual work.
}
现在,您可以清楚地了解问题了。即使注释末尾的超文本链接似乎已在5年前失效,也没关系,因为您仍然可以理解为什么将FindReportsByDate
其替换为FindReportsByDateOnly
。
PerformSqlClient216147Workaround
然后我发现更多信息PerformRightExpressionCast
。毫无疑问,函数的名称是关于它的功能,为什么执行它或如何获得有关它的更多信息。这是一个显式函数,在源代码中将非常容易搜索。
使用错误跟踪系统,该编号可以唯一地标识问题,当您在系统中拉出该错误时,它会提供所需的所有详细信息。这是在源代码中做的非常聪明的事情,当试图了解进行更改的原因时,它将为将来的开发人员节省时间。
如果您在源代码中看到很多这些函数名,那么问题就不在于您的命名约定。问题是您有错误的软件。
您同事的建议有价值。它通过将代码更改与错误代码中记录在错误数据库中的原因(进行更改的原因)相关联来提供可追溯性。
但是,这也表明该功能存在的唯一原因是解决该错误。那就是,如果问题不是问题,则您不希望软件执行该操作。大概您确实希望软件执行其任务,因此函数的名称应说明其功能以及为什么需要执行此问题域;不是错误数据库为什么需要它。该解决方案应该看起来像应用程序的一部分,而不是创可贴。
在临时解决方法的方法名称中包含错误号是否被视为不良做法?
是。
理想情况下,您的班级应该最好地映射/实现应用程序流程/状态中的概念。此类的API名称应反映它们对类状态所做的工作,以便客户端代码可以轻松使用该类(即,除非您特别阅读该名称,否则请不要指定从字面意义上讲没有任何意义的名称)。
如果该类的公共API的一部分基本上说“执行文档/位置X中描述的操作Y”,那么其他人理解API的能力将取决于:
他们知道在外部文档中寻找什么
他们知道在哪里寻找外部文档
他们花费时间和精力,并真正地寻找。
再说一遍,您的方法名称甚至都没有提到此缺陷所在的“位置X”。
它只是假设(没有任何现实原因)每个访问代码的人,也都可以访问缺陷跟踪系统,并且只要稳定的代码存在,跟踪系统仍将存在。
至少,如果您知道该缺陷始终可以在同一位置访问并且不会改变(例如,过去15年中使用相同URL的Microsoft缺陷编号),则应提供指向该缺陷的链接。 API文档中的问题。
即使这样,也可能存在其他缺陷的解决方法,这些缺陷的影响远大于一类的API。那你要怎么办
在多个类中使用具有相同缺陷编号的API(data = controller.get227726FormattedData(); view.set227726FormattedData(data);
实际上并不能告诉您太多,只会使代码更加晦涩难懂。
您可以通过使用描述operation(data = controller.getEscapedAndFormattedData(); view.setEscapedAndFormattedData(data);
)的名称来确定是否解决了所有其他缺陷,除非您的216147缺陷(这违反了“最少惊讶”的设计原理,或者如果您这样说,增加代码的“ WTF / LOC”的大小)。
TL; DR:不好的做法!去你的房间!
对我而言,在错误后命名方法表明该错误未解决或根本原因未确定。换句话说,它表明仍然存在一个未知数。如果您要解决第3方系统中的错误,那么您的解决方法是一种解决方案,因为您知道原因-他们只是无法解决,也无法解决。
如果与SqlClient交互的一部分要求您执行正确的表达式转换,则您的代码应显示为“ performRightExpressionCast()”。您总是可以注释代码以解释原因。
我花了过去四年半的时间来维护软件。使代码在进入时难以理解的一件事是仅由于历史而编写的代码。换句话说,如果今天写的话,那将是行不通的。我指的不是质量,而是观点。
我的一位同事曾经说过:“修复缺陷时,请按原本的方式编写代码。” 我的解释方式是“将代码更改为如果该错误不存在,将如何显示。”
后果:
源代码不需要告诉我它如何达到当前状态。版本控制可以告诉我历史。我需要源代码简单地处于工作所需的状态。就是说,偶尔出现“ // bug 12345”注释不是一个坏主意,但会被滥用。
因此,在决定是否将方法命名为“ PerformSqlClient216147Workaround”时,请问自己以下问题: