Seductive Code 诱人代码
在编写代码和设计API时,平衡权衡是非常谨慎的。 这里有一些日常的Java代码:
for (Protocol protocol : protocols) {
if (protocol != Protocol.HTTP_1_0) {
result.writeByte(protocol.toString().length());result.writeUtf8(protocol.toString());} }
在Android上,垃圾回收器成本不一定是可以忽略的 - 我使我的代码稍微更丑,以保存implicitIterator分配:
for (int i = 0, size = protocols.size(); i < size; i++) {
Protocol protocol = protocols.get(i);if (protocol != Protocol.HTTP_1_0) {
result.writeByte(protocol.toString().length());result.writeUtf8(protocol.toString());} }
Java 8邀请我做出相反的权衡:使用流和lambda类似一个功能的程序员:
protocols.stream() .filter(protocol -> protocol != Protocol.HTTP_1_0).forEach(protocol -> {
result.writeByte(protocol.toString().length());result.writeUtf8(protocol.toString());});
这里我们有三个完全合理的方式来编写相同的代码,因此,对于如何写这个循环有一个不同意见的完美机会。
当编程语言,API或设计模式是诱人的时,变美隐藏其结构限制。 我很沮丧,当我的代码读取更好损害了它的运行效率或可维护性。
诱人和慢
最近我做了一些Python对编程。 它的数组运算符是奇妙的:你可以得到你想要的数据没有仪式。 我们的任务是将一堆值附加到堆栈。 这是我通常写这样的东西:
stack = []
for i in values: stack.append(i)
但我的配对伙伴惊讶我连接:
stack = []
for i in values: stack += [i]
连接代码在数学上是优雅的,但其性能是恶毒的。 我们的循环的每次迭代不必要地复制整个堆栈。 这是一个渴望爆炸的性能炸弹。
诱人和轻薄
Moshi的大部分代码正在应对失败。 我们密切关注当事情断裂时它的行为。 JUnit的预期异常特性使得容易测试失败情况,如int/double类型不匹配:
@Test(expected = JsonDataException.class) public void integerMismatchWithDouble() throws IOException {
JsonReader reader = newReader("[1.5]");reader.beginArray();reader.nextInt(); }
这个功能很容易使用,但我特别不喜欢它。 我的抱怨是,它的简单性限制了测试的效用。 这里有一个更好的:
@Test public void integerMismatchWithDouble() throws IOException {JsonReader reader = newReader("[1.5]");reader.beginArray();try {reader.nextInt();fail();} catch (JsonDataException expected) {assertThat(expected).hasMessage("Expected an int but was 1.5 at path $[0]");}assertThat(reader.nextDouble()).isEqualTo(1.5d);reader.endArray();
}
这个测试更大更好:
它确认nextInt()调用抛出异常。 使用JUnit的预期异常,如果任何行抛出JsonDataException,测试通过。
它确认异常有一个有用的消息。
它确认JsonReader在异常之后处于预期状态。 如果需要,调用代码可以从此故障中恢复。
使用@Test(expected = ...)特性引起你编写松散的测试,因为测试在异常抛出后立即结束。
诱人语法
我喜欢Kotlin。 该语言非常出色,因为您可以编写高效,可维护和可读的代码。 我喜欢它的数据类是简单和能力的不可变类型没有样板。 我喜欢扩展方法如何让我建立新的抽象。
我唯一的抱怨是在一些语法。 这个程序打印什么?
@Test fun test() {val maximumHeightPx = 400val textLineHeight = 100val maxTextBaseline = (maximumHeightPx - textLineHeight) / 2+ textLineHeightprintln(maxTextBaseline)
}
令我惊讶的是,该程序打印150,因为Kotlin的解析+ textineHeight作为一个单独的语句,而不是上一行的延续。
Kotlin的语法诱人地省略了分号。 这看起来不错,但成本太陡了! 空格在Kotlin中很重要,换行可能改变他们的行为。
真正的美
当设计一个API时,要非常小心的包含诱人的功能。 当可读代码也是最快和最有能力的时候,它更好。