在Python、Javascript等动态编程语言中,函数很容易返回一个对象:
def make_vector2(a, b):
return {"x": a, "y": b}
make_vector2
返回的对象的“签名”充当到其他函数的协议或接口。例如:
def norm(v):
return math.sqrt(v["x"]**2 + v["y"]**2)
在程序演化过程中,返回对象的签名可能会发生更改。例如,我会将上面的向量定义更改为{"x0": a, "x1":b}
。
此协议更改可能使其相关功能失效(例如,上述示例中的norm
)。
在静态编程语言中,我有编译器帮助我保持协议的一致性。在动态编程语言中,除非实际运行代码,否则我无法检测问题。
对这个问题有什么建议/好工具吗?
发布于 2015-03-15 18:59:18
喜欢动态语言的人一开始并不认为这是个问题。用于处理这一问题的基本工具只是很好的测试。是的,如果不运行代码,就无法检测到您所描述的问题,因此关键是通过一个好的测试套件运行代码,可能与编译时一样频繁。
当然,这样做也有缺点。如果代码没有经过测试,错误就不会被检测到,而编译器就会捕捉到它。但是你在那里失去的东西,在开发速度和使用松耦合的能力上都有所提高。
当然,在调用norm
时,您的代码会抛出。因此,如果您运行至少一次使用norm
的结果调用make_vector2
的基本测试套件,您将捕获错误。如果您像编译C++或Java程序那样频繁地运行这些测试,那么它实际上并没有什么区别。不管怎样,窃听器都会被抓到。
答案的另一部分是尝试以一种契约更清晰的方式设计代码。例如:
class Vector:
def __init__(self,x,y):
self.x = x
self.y = y
def make_vector2(a, b):
return Vector(a,b)
def norm(v):
return math.sqrt(v.x**2 + v.y**2)
当然,这仍然必须以与原始代码相同的方式进行测试,但这会以早期版本没有的方式记录协议。这意味着您可以执行help(make_vector2)
,并看到它返回带有x
和y
属性的Vector
对象。这就降低了错误发生的可能性。
一般来说,返回原始字典是最好的,当您有意保持松散耦合,因此可以处理更多的变体内容。
发布于 2015-03-15 19:56:15
一种方法是使用软件合同系统,特别是支持功能合同和高级功能合同的系统。一般的想法是使用契约创建工具将一个函数包装成指定“我接受这些类型的值并返回这种值”的规则。它类似于类型系统,但动态检查除外。这种系统的最突出的实现可以在语言Racket中找到,尽管其他动态语言(包括JavaScript和Python )都有实现。
https://softwareengineering.stackexchange.com/questions/276386
复制相似问题