I have seen no "hard and fast" rule on how to check preconditions, but I generally treat it like method documentation. If it is publicly scoped, I assert that the preconditions are met. The logic behind this would be that the scope dictates that you are expecting consumption on a broader scale and with less influence.
Personally, the effort to put assertions around private methods is something I reserve for "mission critical" methods, which would basically be ones that either perform a critical task, are subject to external compliance requirements, or are non-recoverable in the event of an exception. These are largely "judgment calls".
The time saved can be reinvested in thorough unit and integration test enhancement to try and flush out these issues and puts the tooling in place to help enforce the quality of the input assertions as it would be consumed by a client, whether it is a class in your control or not.
I think it depends on how the team is organized: check inputs which come from outside your team.
Check inputs from end-users
Check inputs from software components written by other teams
Trust inputs received from within your own component / within your own team.
The reason for this is for support and maintenance (i.e. bug-fixing): when there's a bug report, you want to be able as quickly as possible to know which component is at fault, i.e. which team to assign the bug to.
if a function is delegating to another function, the first function should check them but checking them again in the second one is redundant.
What if you change the way those functions call each other? Or you introduce new validation requirements in the second function, that the first one delegates to? I'd say it's safer to always check them.
理想情况下,生产系统不会受到断言的影响,您甚至可以使用类似于 Design By Contract(TM) 的机制来静态地释放断言。
I've made the habit of distinguishing between checking and asserting the preconditions, depending (as people pointed out in the comments) on whether a call comes from the outside (unchecked exception, may happen) or the inside (assert, shouldn't happen).
Ideally, the production system won't have the penalty of the asserts, and you could even use a Design By Contract(TM)-like mechanism to discharge the assertions statically.
I think that best practice is to do these checks only if they're going to fail some day. If will help when you do the following.
Debugging
There's no point to check them when several private functions in one module, which has a single maintainer, exchange data. Of course, there are exceptions, especially if your language doesn't have a static type system, or your data are "stringly typed".
However, if you expose public API, one day, someone will fail your precondition. The further is the person that maintains the calling module from you (in organizational structure and in physical location), the more likely it will happen. And when it happens, a clear statement of precondition failure, with a specification where it happened, may save hours of debugging. The Law of Leaky Abstractions is still true...
QA
Precondition failure helps QA to debug their tests. If a unit-test for a module causes the module to yield precondition failure, it means that the test is incorrect, not your code. (Or, that your precondition check is incorrect, but that's less likely).
If one of the means to perform QA is static analysis, then precondition checks, if they have a specific notation (for example, only these checks use assert_precondition macro), will also help. In static analysis it's very important to distinguish incorrect input and source code errors.
Documentation
If you don't have much time to create documentation, you may make your code aid the text that accompanies it. Clear and visible precondition checks, which are perceived separate from the rest of the implementation, "document" possible inputs to some extent. (Another way to document your code this way is writing unit tests).
// C, C++:
void example(char const* s) {
// precondition: s points to a valid null-terminated string
assert(s); // tests that s is non-null, which is required for it to point to
// a valid null-terminated string. the real test is nearly impossible from
// within this function
}
As with everything, evaluate your requirements to find the best solution for each situation.
When preconditions are easier to check ("pointer isn't null"), you might as well do that often. Preconditions which are hard to check ("points to a valid null-terminated string") or are expensive in time, memory, or other resources may be handled a different way. Use the Pareto principle and gather the low-hanging fruit.
// C, C++:
void example(char const* s) {
// precondition: s points to a valid null-terminated string
assert(s); // tests that s is non-null, which is required for it to point to
// a valid null-terminated string. the real test is nearly impossible from
// within this function
}
Guaranteeing preconditions is the responsibility of the caller. Because of this, several languages offer an "assert" construct that can optionally be skipped (e.g. defining NDEBUG for C/C++, command-line switch for Python) so that you can more extensively test preconditions in special builds without impacting final performance. However, how to use assert can be a heated debate—again, figure out your requirements and be consistent.
It is a little bit old question, but no, preconditions do not have to be checked every time. It really depends.
For example, what if you have binary search over vector. Precondition is sorted vector. Now, if you check every time if vector is sorted this takes a linear time (for each vector), so it is not efficient. Client must be aware of precondition and be sure to meet it.
发布评论
评论(9)
我没有看到关于如何检查先决条件的“硬性且快速”的规则,但我通常将其视为方法文档。如果它是公开范围的,我断言满足先决条件。这背后的逻辑是,范围决定了你期望消费规模更大、影响力更小。
就我个人而言,围绕私有方法进行断言的努力是我为“关键任务”方法保留的,这些方法基本上是执行关键任务、遵守外部合规性要求或在发生异常情况时不可恢复的方法。例外。这些很大程度上是“判断电话”。
节省的时间可以重新投入到彻底的单元和集成测试增强中,以尝试解决这些问题,并使用工具来帮助提高输入断言的质量,因为它会被客户端使用,无论它是一个类你是否能控制。
I have seen no "hard and fast" rule on how to check preconditions, but I generally treat it like method documentation. If it is publicly scoped, I assert that the preconditions are met. The logic behind this would be that the scope dictates that you are expecting consumption on a broader scale and with less influence.
Personally, the effort to put assertions around private methods is something I reserve for "mission critical" methods, which would basically be ones that either perform a critical task, are subject to external compliance requirements, or are non-recoverable in the event of an exception. These are largely "judgment calls".
The time saved can be reinvested in thorough unit and integration test enhancement to try and flush out these issues and puts the tooling in place to help enforce the quality of the input assertions as it would be consumed by a client, whether it is a class in your control or not.
我认为这取决于团队的组织方式:检查来自团队外部的输入。
这样做的原因是为了支持和维护(即错误修复):当有错误报告时,您希望能够尽快知道哪个组件出了问题,即将错误分配给哪个团队。
I think it depends on how the team is organized: check inputs which come from outside your team.
The reason for this is for support and maintenance (i.e. bug-fixing): when there's a bug report, you want to be able as quickly as possible to know which component is at fault, i.e. which team to assign the bug to.
根据我的经验,这取决于您的封装。
如果内部函数是私有的,那么您可以非常确定它的前提条件已设置。
猜猜这都是关于德米特法则的,只和你的朋友说话等等。
作为最佳实践的基础,如果通话是公开的,您应该检查您的输入。
In my experience, it depends on your encapsulation.
If the inner function is private then you can be pretty sure that its preconditions are set.
Guess it's all about the Law of Demeter, talk only to your friends and so on.
As a basis for best practise, if the call is public, you should check your inputs.
如果改变这些函数相互调用的方式会怎样?或者您在第一个函数委托的第二个函数中引入新的验证要求?我想说的是,经常检查它们会更安全。
What if you change the way those functions call each other? Or you introduce new validation requirements in the second function, that the first one delegates to? I'd say it's safer to always check them.
我养成了区分先决条件检查和断言的习惯,这取决于(正如人们在评论中指出的那样)调用是否来自外部(未经检查的异常,可能发生)或内部(断言,不应该发生)。
理想情况下,生产系统不会受到断言的影响,您甚至可以使用类似于 Design By Contract(TM) 的机制来静态地释放断言。
I've made the habit of distinguishing between checking and asserting the preconditions, depending (as people pointed out in the comments) on whether a call comes from the outside (unchecked exception, may happen) or the inside (assert, shouldn't happen).
Ideally, the production system won't have the penalty of the asserts, and you could even use a Design By Contract(TM)-like mechanism to discharge the assertions statically.
我认为最佳实践是仅当这些检查有一天会失败时才进行这些检查。当您执行以下操作时,如果会有所帮助。
调试
当一个模块(只有一个维护者)中的多个私有函数交换数据时,检查它们是没有意义的。当然,也有例外,特别是如果您的语言没有静态类型系统,或者您的数据是“字符串类型”。
然而,如果你公开公共API,有一天,有人会满足你的前提条件。维护呼叫模块的人距离您越远(在组织结构和物理位置上),发生这种情况的可能性就越大。当发生这种情况时,明确说明前提条件失败并说明发生的位置,可能会节省数小时的调试时间。 泄漏抽象法则仍然正确...
QA
前提条件失败有助于 QA 调试他们的测试。如果模块的单元测试导致模块产生前提条件失败,则意味着测试不正确,而不是您的代码不正确。 (或者,您的前提条件检查不正确,但这种可能性较小)。
如果执行 QA 的方法之一是静态分析,那么前置条件检查如果有特定的符号(例如,只有这些检查使用
assert_precondition
宏),也将帮助。在静态分析中,区分不正确的输入和源代码错误非常重要。文档
如果您没有太多时间创建文档,您可以让您的代码辅助其随附的文本。清晰可见的前提条件检查被认为与实现的其余部分分开,在某种程度上“记录”了可能的输入。 (以这种方式记录代码的另一种方法是编写单元测试)。
I think that best practice is to do these checks only if they're going to fail some day. If will help when you do the following.
Debugging
There's no point to check them when several private functions in one module, which has a single maintainer, exchange data. Of course, there are exceptions, especially if your language doesn't have a static type system, or your data are "stringly typed".
However, if you expose public API, one day, someone will fail your precondition. The further is the person that maintains the calling module from you (in organizational structure and in physical location), the more likely it will happen. And when it happens, a clear statement of precondition failure, with a specification where it happened, may save hours of debugging. The Law of Leaky Abstractions is still true...
QA
Precondition failure helps QA to debug their tests. If a unit-test for a module causes the module to yield precondition failure, it means that the test is incorrect, not your code. (Or, that your precondition check is incorrect, but that's less likely).
If one of the means to perform QA is static analysis, then precondition checks, if they have a specific notation (for example, only these checks use
assert_precondition
macro), will also help. In static analysis it's very important to distinguish incorrect input and source code errors.Documentation
If you don't have much time to create documentation, you may make your code aid the text that accompanies it. Clear and visible precondition checks, which are perceived separate from the rest of the implementation, "document" possible inputs to some extent. (Another way to document your code this way is writing unit tests).
与所有事情一样,评估您的要求以找到适合每种情况的最佳解决方案。
当先决条件更容易检查时(“指针不为空”),您不妨经常这样做。难以检查的先决条件(“指向有效的空终止字符串”)或耗费时间、内存或其他资源的先决条件可以以不同的方式处理。使用帕累托原则并收集唾手可得的果实。
保证先决条件是调用者的责任。因此,多种语言提供了可以选择跳过的“断言”构造(例如,为 C/C++ 定义 NDEBUG、为 Python 定义命令行开关),以便您可以在特殊构建中更广泛地测试前提条件,而不会影响最终性能。然而,如何使用断言可能是一个激烈的争论——再次强调,弄清楚你的需求并保持一致。
As with everything, evaluate your requirements to find the best solution for each situation.
When preconditions are easier to check ("pointer isn't null"), you might as well do that often. Preconditions which are hard to check ("points to a valid null-terminated string") or are expensive in time, memory, or other resources may be handled a different way. Use the Pareto principle and gather the low-hanging fruit.
Guaranteeing preconditions is the responsibility of the caller. Because of this, several languages offer an "assert" construct that can optionally be skipped (e.g. defining NDEBUG for C/C++, command-line switch for Python) so that you can more extensively test preconditions in special builds without impacting final performance. However, how to use assert can be a heated debate—again, figure out your requirements and be consistent.
这是一个有点老的问题,但是不,不必每次都检查先决条件。这确实取决于。
例如,如果您对向量进行二分搜索会怎样。前提条件是排序向量。现在,如果每次检查向量是否已排序,这需要线性时间(对于每个向量),因此效率不高。客户必须了解先决条件并确保满足它。
It is a little bit old question, but no, preconditions do not have to be checked every time. It really depends.
For example, what if you have binary search over vector. Precondition is sorted vector. Now, if you check every time if vector is sorted this takes a linear time (for each vector), so it is not efficient. Client must be aware of precondition and be sure to meet it.
最佳做法是始终检查它们。
The best practice is to always check them.