Your test suite is trying to tell you something
blog.jgc.org
blog.jgc.org
Having said that it doesn't change the fact that looking into the 'flaky' test was the right thing to do. Even if the type system were different I'm sure I would have shot myself in the foot in some other way.
The idea of storing this information as just a regular Int64 bothers me after spending so much time in type system nirvana.
Its not a regular int64, its a distinct named type (Duration) where int64 is the underyling time. I'm still getting familiar with Go -- and don't have it on the machine I'm using at the moment -- but from the docs named types are incompatible with other named types with the same underlying types in numerous contexts, but it looks like one place where named types are leaky abstractions is their interaction with operators.
package main
import (
"time"
"fmt"
)
func ident(x int64) int64 {
return x
}
func main() {
t := time.Duration(1)
v := math.Inf(t)
}
produces the error: cannot use t (type time.Duration) as type int64 in function argument
The issue is with Go's arithmetic operators subverting the type system more than with the type system itself.I hate that SCM systems commonly describe who made changes as "blame" (couldn't it be "praise" for when you want to find out who wrote exceptional code?) and yet it's wonderful to be able to look back into history and see "who" was responsible for a block of code. It can be a real learning experience!
"...a person who came along from my team whose whole job during the meeting was to keep an accurate count of how many times Bill said the F word. The lower the f*-count, the better."
(this is what I unfortunately sit right in the middle of)
If there's no common code to connect, and every user of it has its own implementation, there might be more bugs like this lurking. Every user of memcache in this particular code base would need to have its own "what if memcached is slow or down?" type test. It seems such a test did not already exist.
Following the events in this post, is there now a test to explicitly make sure the delays are reasonable, or was the extra multiplication just removed?
It's amazing what you will learn if you pay attention to the pain.
I guess it depends on the culture within your team, how much you all care about your test suites.
Software doesn't fail spuriously – there's always a cause.
This particular bug is also a strong argument for using more advanced type systems, even if you have good test coverage.
struct duration { int in_nanoseconds; };
struct duration seconds_duration (int in_seconds) {
struct duration dt;
dt.in_nanoseconds = in_seconds * 1000000000;
return dt;
}
/*TODO: milliseconds_duration(), microseconds_duration(), etc */Yes, it's a great pity that the compiler didn't say "You're multiplying a time.Duration by a time.Duration and expecting it to be a time.Duration".
In this case, that's not what's going on, though. It's multiplying time by unitless scaling factor, which doesn't present the same problem. However, there's a few ways you can get at the issue with the help of the language, you just have to distinguish between the different units you might be using to represent time - this doesn't really take an advanced type system: the example of having a .milliseconds method is along these lines.
It seems that sometimes a netty hashwheeltimer is executing a timeout you add immediately, instead of after 2 seconds. And its the simplest code, and the 2 seconds we are trying to set are literals, so it ready surprises me. Find it hard to imagine a bug in netty and it always affects the same test, despite all our requests setting an aggressive 2 second timeout...
http://memcached.org/ -- the URL has a d (unlike mysql)
"What is Memcached?" -- it's how they talk about themselves.
It's even in the logo...
type Inch = int type Centimeter = int
And then have the compiler enforce these as different types (as opposed to alias'es), so if you want to use an Inch, where the function decalares it expects a Centimeter, you would be force to cast it (or have the compiler auto cast using your conversion function).
This doesn't get you support for multidimensional units (IE, define a function that goes from arbitary unit u to u^2), which would require a much more complicated addition to the type system.
Go has support for cheap type aliases for which names typed with the same underlying type are distinct types which are not mutually assignable, and, in fact, Duration is such a type with int64 as the underlying type.